Я, или студейа? Код (Text): struct HaveDefaultConstructor { HaveDefaultConstructor() {} }; struct HaveNoDefaultConstructor { }; template <class T> struct Foo { T t; int x; }; int main() { Foo<HaveDefaultConstructor> foo1 = Foo<HaveDefaultConstructor>(); Foo<HaveNoDefaultConstructor> foo2 = Foo<HaveNoDefaultConstructor>(); return 0; } foo1.x инициализируется, а foo2.x - нет. А как должно быть и почему?
Только наоборот. foo2.x инициализируется нулём, а foo1.x не инициализируется и сохраняет своё значение 0xcccccccc, которое там появилось после выполнения пролога. А вот почему именно так - х.з. Надо подумать.
[maxdiver IMHO порядок объявления важен. Вроде студия не предупреждает об этом -). gcc об этом предупреждает - пишет что возможны проблемы в порядке инициализации. Хотя может надо уровень ворнингов повыше сделать.
maxdiver Да, прошу прощения, перепутал. Наоборот. Booster Поведение ясно - Если среди мемберов, включая любую вложенность, есть объект, имеющий конструктор по умолчанию, то базовые типы не инициализируются через явную инициализацию. Вопрос в том, прочему это происходит. Так и должно быть, или это студия тупит.
_DEN_ Со Стандартом пока не сверялся. Но попробовал Intel C++ 9.0 - там обе структуры инициализируются нулями. Вообще, было бы странно, если поведение MS VC было бы стандартным, ИМХО это его баго-фича. Booster А причём тут порядок объявления/инициализации? Когда инициализация уже полностью завершена, переменная в одном случае остается неинициализированной.
_DEN_ Вот что говорит Стандарт: Т.е. должна быть инициализация нулями в обоих случаях, насколько я понимаю.
Видимо, опять MS VS прав Похоже, что по Стандарту он не обязан инициализировать члены встроенных типов, поэтому и если в члене оказался 0, и если оказалось 0xcccccccc, - оба поведения являются стандартными, и значение в общем случае не определено. Чтобы не быть голословным, приведу выдержку из Стандарта (тем более что я, как всегда, не уверен в своём английском ): P.S. 2green у нас разные стандарты?
На сколько я понимаю, должно быть так: A a; // Базовые мемберы не инициализируются. A a = A(); // Инициализируются нулями. Аналог: A* a = new A; и A* a = new A();
maxdiver Обрати внимание, что Foo не имеет конструктора. Т.е. твоя цитата здесь неприменима. _DEN_ В случае, когда A имеет конструктор, никакой неявной инициализации не происходит, т.е. new A и new A() эквивалентны. Если конструктор отсутствует, то при new A() инициализация нулями происходит, а при new A - нет.
green RedLord Так ведь конструктор всё равно есть, он автоматически генерируется компилятором. Значит, на него должны распространяться те же требования, что и на обычный конструктор? Или я чего-то не понимаю?
maxdiver насколько я понял, описывается ситуация, если в списке инициализации явно опреденного конструктора пропущен, тот или иной мембер struct A { A():x(0) // а про "y" и "s" забыли { } int x; int y; std::string s; };
green Дыг блин - А и не имеет явного конструктора. Поведение мемберов А при инициализации получается зависит от того, есть ли явный конструктор у других мемберов А. У самого А явного конструктора как не было так и нет.
_DEN_ Конечно не имеет, я о чём и говорю. Т.е. и foo1.x, и foo2.x должны инициализироваться нулями. Стало быть, бага в VC++.
_DEN_ Ну, насколько я понял Стандарт. Надо бы на других компиляторах проверить, на Comeau особенно. У меня только VC8 и Интел 9 под рукой. maxdiver уже писал, что Intel инициализирует и foo1, и foo2.
green Ты приводишь цитату из стандарта, но она про статические объекты, а речь идет об автоматических. Стандарт не гарантирует инициализацию автоматических переменных интегральных типов. Простейший пример: Код (Text): int i; int main() int i; cout << ::i << ' ' << i << '\n'; return 0; } Первое i получается 0, ибо статическое, а во втором теоретически может получится все что угодно. Для членов класса (а здесь обсуждаются именно члены, а не базы, как сказано в названии темы) не инициализированых явно вызываются конструкторы по умолчанию, но к и интегральным типам это не относится, так как у них конструкторов нет. Т.е. если переписать изначальный пример вот так: Код (Text): struct HaveDefaultConstructor { HaveDefaultConstructor() {} }; struct HaveNoDefaultConstructor { }; template <class T> struct Foo { T t; int x; }; Foo<HaveDefaultConstructor> foo1 = Foo<HaveDefaultConstructor>(); Foo<HaveNoDefaultConstructor> foo2 = Foo<HaveNoDefaultConstructor>(); int main() { return 0; } мы наверняка получим обнуление. А что касается автоматических переменных - детали реализации. MicroSoft'овские компиляторы очень сильны в плане оптимизации, поэтому (и потому что) избегают лишних действий. В любом случае использование неинициализированой переменной - очень дурной тон. Кстати в приведенном примере в MSVC 7.0 при попытке обращения к foo2 в Debug'е вылетает исключение: Run-Time Check Failure #3 - The variable 'foo2' is being used without being defined.
2all Так где же правильная цитата? А то по одной цитате - нужно заполнять нулями, по другой - не нужно. А может, есть и ещё какой-нибудь пунктик стандарта? Ustus Ну дык вопрос как раз в том и состоит: детали ли это реализации или общее стандартное требование?
Ustus Где указано, что определение value-инициализации из 8.5 касается только статических объектов ? А вот для default-инициализации автоматических объектов, отличных от non-POD class type (т.е. в т.ч. и интегральных), есть специальное правило: