Инициализация базовых типов: кто тупит?

Тема в разделе "LANGS.C", создана пользователем _DEN_, 21 май 2007.

  1. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Я, или студейа?

    Код (Text):
    1. struct HaveDefaultConstructor
    2. {
    3.     HaveDefaultConstructor() {}
    4. };
    5.  
    6. struct HaveNoDefaultConstructor
    7. {
    8.  
    9. };
    10.  
    11. template <class T>
    12. struct Foo
    13. {
    14.     T   t;
    15.     int x;
    16. };
    17.  
    18. int main()
    19. {
    20.     Foo<HaveDefaultConstructor>   foo1 = Foo<HaveDefaultConstructor>();
    21.     Foo<HaveNoDefaultConstructor> foo2 = Foo<HaveNoDefaultConstructor>();
    22.  
    23.     return 0;
    24. }
    foo1.x инициализируется, а foo2.x - нет. А как должно быть и почему?
     
  2. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Только наоборот.
    foo2.x инициализируется нулём, а foo1.x не инициализируется и сохраняет своё значение 0xcccccccc, которое там появилось после выполнения пролога.
    А вот почему именно так - х.з. Надо подумать.
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    [maxdiver
    IMHO порядок объявления важен.
    Вроде студия не предупреждает об этом -).
    gcc об этом предупреждает - пишет что возможны проблемы в порядке инициализации.
    Хотя может надо уровень ворнингов повыше сделать.
     
  4. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    maxdiver

    Да, прошу прощения, перепутал. Наоборот.


    Booster

    Поведение ясно - Если среди мемберов, включая любую вложенность, есть объект, имеющий конструктор по умолчанию, то базовые типы не инициализируются через явную инициализацию. Вопрос в том, прочему это происходит. Так и должно быть, или это студия тупит.
     
  5. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    _DEN_
    Со Стандартом пока не сверялся. Но попробовал Intel C++ 9.0 - там обе структуры инициализируются нулями.
    Вообще, было бы странно, если поведение MS VC было бы стандартным, ИМХО это его баго-фича.

    Booster
    А причём тут порядок объявления/инициализации? Когда инициализация уже полностью завершена, переменная в одном случае остается неинициализированной.
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Вот что говорит Стандарт:
    Т.е. должна быть инициализация нулями в обоих случаях, насколько я понимаю.
     
  7. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    Видимо, опять MS VS прав :)
    Похоже, что по Стандарту он не обязан инициализировать члены встроенных типов, поэтому и если в члене оказался 0, и если оказалось 0xcccccccc, - оба поведения являются стандартными, и значение в общем случае не определено.
    Чтобы не быть голословным, приведу выдержку из Стандарта (тем более что я, как всегда, не уверен в своём английском :) ):

    P.S. 2green у нас разные стандарты? :)
     
  8. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    maxdiver
    разве речь не про явно определенный констуктор?
    struct A
    {
    A():x(0)
    {
    }
    int x;
    };
     
  9. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    На сколько я понимаю, должно быть так:

    A a; // Базовые мемберы не инициализируются.

    A a = A(); // Инициализируются нулями.

    Аналог:

    A* a = new A;

    и

    A* a = new A();
     
  10. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    maxdiver
    Обрати внимание, что Foo не имеет конструктора. Т.е. твоя цитата здесь неприменима.

    _DEN_
    В случае, когда A имеет конструктор, никакой неявной инициализации не происходит, т.е.
    new A и new A() эквивалентны.
    Если конструктор отсутствует, то при new A() инициализация нулями происходит, а при new A - нет.
     
  11. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    green
    RedLord
    Так ведь конструктор всё равно есть, он автоматически генерируется компилятором. Значит, на него должны распространяться те же требования, что и на обычный конструктор? Или я чего-то не понимаю?
     
  12. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    maxdiver
    насколько я понял, описывается ситуация, если в списке инициализации явно опреденного конструктора пропущен, тот или иной мембер
    struct A
    {
    A():x(0) // а про "y" и "s" забыли
    {
    }
    int x;
    int y;
    std::string s;
    };
     
  13. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Дыг блин - А и не имеет явного конструктора. Поведение мемберов А при инициализации получается зависит от того, есть ли явный конструктор у других мемберов А. У самого А явного конструктора как не было так и нет.
     
  14. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Конечно не имеет, я о чём и говорю. :)
    Т.е. и foo1.x, и foo2.x должны инициализироваться нулями. Стало быть, бага в VC++.
     
  15. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    green

    Это 102% ?
     
  16. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    _DEN_
    Ну, насколько я понял Стандарт. :derisive:
    Надо бы на других компиляторах проверить, на Comeau особенно. У меня только VC8 и Интел 9 под рукой. maxdiver уже писал, что Intel инициализирует и foo1, и foo2.
     
  17. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    green
    Comeau 4.3.9. - нули в обоих случаях
     
  18. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    green
    Ты приводишь цитату из стандарта, но она про статические объекты, а речь идет об автоматических. Стандарт не гарантирует инициализацию автоматических переменных интегральных типов. Простейший пример:
    Код (Text):
    1. int i;
    2.  
    3. int main()
    4.     int i;
    5.     cout << ::i << ' ' << i << '\n';
    6.     return 0;
    7. }
    Первое i получается 0, ибо статическое, а во втором теоретически может получится все что угодно. Для членов класса (а здесь обсуждаются именно члены, а не базы, как сказано в названии темы) не инициализированых явно вызываются конструкторы по умолчанию, но к и интегральным типам это не относится, так как у них конструкторов нет.

    Т.е. если переписать изначальный пример вот так:
    Код (Text):
    1. struct HaveDefaultConstructor
    2. {
    3.     HaveDefaultConstructor() {}
    4. };
    5.  
    6. struct HaveNoDefaultConstructor
    7. {
    8.  
    9. };
    10.  
    11. template <class T>
    12. struct Foo
    13. {
    14.     T   t;
    15.     int x;
    16. };
    17.  
    18. Foo<HaveDefaultConstructor>   foo1 = Foo<HaveDefaultConstructor>();
    19. Foo<HaveNoDefaultConstructor> foo2 = Foo<HaveNoDefaultConstructor>();
    20.  
    21. int main()
    22. {
    23.     return 0;
    24. }
    мы наверняка получим обнуление.
    А что касается автоматических переменных - детали реализации. MicroSoft'овские компиляторы очень сильны в плане оптимизации, поэтому (и потому что) избегают лишних действий. В любом случае использование неинициализированой переменной - очень дурной тон.

    Кстати в приведенном примере в MSVC 7.0 при попытке обращения к foo2 в Debug'е вылетает исключение:
    Run-Time Check Failure #3 - The variable 'foo2' is being used without being defined.
    :):):)
     
  19. maxdiver

    maxdiver Max

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    308
    Адрес:
    Саратов
    2all
    Так где же правильная цитата? А то по одной цитате - нужно заполнять нулями, по другой - не нужно. А может, есть и ещё какой-нибудь пунктик стандарта? :)

    Ustus
    Ну дык вопрос как раз в том и состоит: детали ли это реализации или общее стандартное требование?
     
  20. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Ustus
    Где указано, что определение value-инициализации из 8.5 касается только статических объектов ?
    А вот для default-инициализации автоматических объектов, отличных от non-POD class type (т.е. в т.ч. и интегральных), есть специальное правило: