1. C++ / Говнокод #12669

    +18

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    #include <iostream>
    #include <map>
    
    struct A { 
       const static int i = 10;
    };
    
    using namespace std;
    
    int main()
    {
       map<int, string> m;
       m[0] = "zero";
       m[A::i] = "A::i"; // Не везде работает
       cout << A::i << endl;
       return 0;
    }

    Недели stackoverflow на уютненьньком.
    Почему-то этот код не собирается в GCC 4.7.2, но при этом работает в 4.6.3 и 4.8.0.
    http://liveworkspace.org/code/2o5qOP$1
    http://liveworkspace.org/code/2o5qOP$2
    http://liveworkspace.org/code/2o5qOP$3

    Запостил: absolut, 01 Марта 2013

    Комментарии (49) RSS

    • баг компилятора?
      Ответить
      • Да, баг в том что 4.8.0 и 4.6.3 не ругаются (см. мой коммент ниже).

        P.S. Кстати у меня и 4.6.3 тоже не собирает с ошибкой undefined reference to `A::i'.
        Ответить
        • Кстати, я тоже вот локально проверяю на 4.4.2/4.6.3/4.7.2 - везде ругается. А вот MS VS 2010 собирает.
          Я не очень понял, что следует из стандарта и этой связи с компиляторным багизмом.
          Интересно, что если использовать идентификатор просто для вывода, то он считается определенным, а если как ключ для мапы - то хуй.
          Ответить
          • Ну как я понял стандарт - целочисленные статические константы можно использовать в любом месте, где требуется константа - case в свиче, для инициализации других констант и т.п. Компилятор ругаться не будет.

            Но если мы юзаем эту константу где-то в другом месте, где константность не обязательна - компилятор может не захотеть подставлять ее значение, а оставит ее как обычную переменную, и тут то линкер свалится с ошибкой "undefined reference".

            P.S. А может и подставить, и тогда все будет компилиться и работать, откладывая баттхерты на потом.
            Ответить
            • чем концептуально отличается m[A::i] от cout << A::i ?
              Ответить
              • Имхо просто рандомные эффекты от оптимизатора. В одном случае компилятору захотелось подставить значение, и он подставил. В другом - не захотелось, оставил как переменную, и линкер упал.
                Ответить
                • Т.е. дело в ссылке, а не в оптимизации? или и то, и другое?
                  всё-таки странно, что на разных версиях GCC сначала не работает - потом работает - потом опять не работает. (судя по liveworkspace).
                  Мне это даже напомнило цитатку из вики про #pragma once http://en.wikipedia.org/wiki/Pragma_once:
                  GCC originally gave a warning declaring #pragma once "obsolete" due to a problem with symbolic and hard links. However, this problem was fixed in GCC 3.4, and the feature was "un-deprecated" and the warning removed.
                  Ответить
                  • И то и другое. Если компилятору взбредет в голову заинлайнить функцию, в которую константу передали по ссылке - все соберется. Если же он захочет вызвать ее по-настоящему, то ему сподручней будет передать ссылку на A::i. Не мутить же отдельную переменную только ради этого? Вот тогда мы и увидим данную ошибку.

                    На самом деле, если следовать стандарту, проблема не так ужасна. Юзаешь только в тех местах, где допустимы только константы? Достаточно будет struct A { const int i = 100500 }. Юзаешь где-то еще? Добавляй в сипипишку, посвященную данному классу const int A::i.
                    Ответить
              • Кажется понял - оператор [] принимает аргумент по ссылке. Поэтому компилер и передал ее туда. Пруф:
                https://ideone.com/zQDd5H
                https://ideone.com/Zc7sLF
                https://ideone.com/6Oaow3
                Ответить
                • C++. Удивительные открытия каждый день.

                  Ничего не понимаю, и это компилятор. Говно какое-то, недетерминированное, блядь. Ему статику в неймспейсе дали- подставляй. Подставляй константы, блядь!
                  Не хочу, хочу передавать как undefined reference! Что такое? Это С++? Это С++? Оптмизации включил, по ссылке передаёт - пидор ебучий, блядь.
                  Ответить
                  • С++ - это девушка неопределённого поведения.
                    Ответить
                    • Не успел отредактировать что цитата из к/ф "Зеленые крестики"
                      Ответить
                      • к\ф "Зеленый слоник"?
                        Ответить
                        • Подозреваю что Тарас выучил кресты, только из-за отличной срачепригодности.
                          Как показала практика шитштормы устраивались из-за пары, а иногда и одной строчки.
                          Потому С++
                          Ответить
                        • Что за "зеленый слоник"? За сегодня второй раз про него слышу.
                          Ответить
                  • не переживай так, в с++03 вообще кроме интегральных констант хуй че объявишь прямо в классе, надо вне класса в .cpp файле херачить
                    так что 1) вместо static const int пользуйся enum, врядли тебе нужен будет где то _адрес_, а не значение
                    2) раз уж все равно большую часть присваивать вне класса, почему бы всё не присваивать вне класса

                    и да, в студии код из ОП работает, понятное дело
                    Ответить
                    • > в студии код из ОП работает, понятное дело
                      Работоспособность этого кода не противоречит стандарту... равно как и неработоспособность.

                      P.S. Хотя гарантированно работающим он бы мне больше нравился.
                      Ответить
                      • Кстати, студия 2008 принимает rvalue (временные объекты) по неконстантной ссылке в функции о_О.

                        PS: Роман уже отписался ниже
                        Ответить
                        • А если отключить расширения языка от майкрософта? Была там такая опция.
                          Ответить
                    • P.P.S. Кстати, в студии этот код работает, или обязан работать?
                      Ответить
                    • *ROFL* MSVC 2005 запрещает добавлять const int A::i; в cpp файл, под предлогом already defined. MS как всегда не читало стандарт хочет затруднить портирование на другие компилеры заботится о программистах...
                      Ответить
                    • В студии много всякой гадости работает без ворнингов. В 2005, к примеру, можно передавать временные объекты по неконстантным ссылкам, даже ворнинга не будет.
                      Ответить
                      • Да они в 2005 году только с циклом for (int i=0; i<10; i++) до конца разобрались... Какие уж тут ссылки.

                        P.S. Забавно было смотреть, как мой корректный код
                        for (int i=0; i<10; i++) { }
                        for (int i=0; i<10; i++) { }
                        который, к слову, работал в шестой визуалке, отвергался 2003й потому что "ISO сменило скопы", и единственным портабельным способом между 6, 2003 и 2005 был старый добрый сишный
                        int i;
                        for (i=0; i<10; i++) {}
                        for (i=0; i<10; i++) {}
                        Ответить
                        • Сорри, зря я ругался на 2003, у нее есть force conformance in loop scope, с которым for работает как положено.
                          Ответить
                      • > можно передавать временные объекты по неконстантным ссылкам
                        и не только в 2005
                        в этом плане я придерживаюсь следующего:
                        собственно, в чем проблема - ну временный объект, ну поменяет его функция - функции то всё равно насрать, что станет с тем объектом, а если мы туда передали временный объект - значит и нам насрать
                        Ответить
                        • Чем бы функция не тешилась, лишь бы указатель не сохранила.
                          Ответить
                  • У меня в проекте был похожий код. Я долго тупил и не мог понять, почему невинное выражение
                    prop_tree.get<uint32_t>(PARAM_NAME, DEFAULT);
                    не компилируется. Оказалось, get() принимает аргумент по ссылке, а у константы нет адреса.
                    Кресты...
                    Ответить
                    • > а у константы нет адреса

                      У констант есть адрес.
                      А вот передать константу как переменную по ссылке не получится.
                      Ответить
                      • У интегральной константы времени компиляции нет адреса.
                        Ответить
    • C++98, 9.4.2. Static data members
      If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.
      Ответить
    • Гцц 4.7.2, видимо, заявляет, что определение статических констант-членов структуры следует производить вне определения самой структуры.

      Следующий вариант решает проблему:
      struct A
      { 
         const static int i; /* only declaration */
      };
      
      const int A::i = 10; /* define a constant */
      Ответить
      • Судя по стандарту (цитата комментом выше) для целочисленных типов и енумов можно и так:
        // test.h
        struct A {
            const static int i = 10;
        };
        // test.cpp
        const int A::i;
        И можно опустить definition в случаях если мы не юзаем эту константу в коде, а юзаем только в константных выражениях. Так что гцц прав.
        Ответить
        • >а юзаем только в константных выражениях
          теперь я кажется понял, почему кушает в cout.
          p.s. или не понял :)
          Ответить
    • Чё, такое компилируется?
      Ответить
    • КРЕСТОПРОБЛЕМЫ
      Ответить
    • Вот честно, никогда не понимал как можно называть стандартом документ где чуть-ли в каждом абзаце упоминается неопределенное поведени.
      Ответить
      • Драфт языка UB++:
        1. Undefined behavior.
        1.1. Behavior of any UB++ program is undefined.
        Ответить
        • 1.2. You do not talk about Undefined behavior.
          1.3. You DO NOT talk about Undefined behavior!
          Ответить
    • > m[A::i]
      причудился питоновский срез...
      Ответить
    • In any case, just because code is syntactically "valid" GNU C doesn't mean gcc can always compile it. <...>
      The fact that it works at O3 is pure luck and not a bug.

      gcc.gnu.org/bugzilla/show_bug.cgi?id=11203

      Я понимаю что это кресты, но речь об отношении gcc в целом.
      Ответить
      • > Я понимаю что это кресты
        А при чем тут кресты? Проблема же вылезла уже при раздаче регистров: "error: can't find a register in class 'GENERAL_REGS' while reloading 'asm'", на этом этапе никаких крестов уже нет.

        А автор, имхо, сам виноват: там в конце инлайн вставки слишком дохера "m" параметров. Т.к. многие из описанных там кусков памяти находятся не в стековом фрейме и не в глобалках, компилятор должен поместить их адрес перед асмовставкой в какой-то регистр (т.к. он не имеет права добавлять дополнительные инструкции внутрь вставки). А регистров на x86 мало (всего 8, из которых 2 заняты стеком (esp) и стековым фреймом (ebp) (т.к. на -O0 выключен -fomit-frame-pointer)).
        Ответить

    Добавить комментарий