БОЛЬШАЯ ошибка VС++? Почему список-инициализаторов не инициализирует структуру по значению?

Стандарт С++ 11 8.5.4.3 гласит:

«Если в списке инициализаторов нет элементов, а T является типом класса с конструктором по умолчанию, объект инициализируется значением».

struct A
{
    int get() { return i; }

private:
    int i;
};

int main()
{
    A a = {};

    int n = a.get();
    cout << n << endl;
    // n is a random number rather than 0

    return 0;
}

Это ошибка VС++? Мой VC++ — это последняя версия CTP от ноября 2012 года.


person xmllmx    schedule 16.12.2012    source источник
comment
Оптимизация компилятора не должна нарушать положения стандарта C++. Так что я думаю, что это не имеет ничего общего с оптимизацией.   -  person xmllmx    schedule 16.12.2012
comment
@KillianDS, пожалуйста, просмотрите мой исправленный пост   -  person xmllmx    schedule 16.12.2012
comment
Что будет напечатано, если вы добавите std::cout << n << std::endl;?   -  person helium    schedule 16.12.2012
comment
Он распечатал 0xCCCCCCCC.   -  person xmllmx    schedule 16.12.2012
comment
Я получаю аналогичное поведение с g++ 4.6.3, но, насколько я могу судить, это неправильное поведение. Ситуация, с которой вы столкнулись, похоже, является вторым случаем раздела 8.5.7, что указывает на то, что произойдет нулевая инициализация.   -  person Vaughn Cato    schedule 16.12.2012
comment
0xCCCCCCCC — это значение по умолчанию в VC++ в отладочной сборке для многих переменных. Он меняется каждый раз при компиляции? Изменится ли это, если вы создадите в режиме выпуска?   -  person RedX    schedule 17.12.2012
comment
Это случайное значение. Я уверен, что структура не инициализирована.   -  person xmllmx    schedule 17.12.2012


Ответы (1)


Инициализация значения неагрегированного типа класса описана в 8.5p8. В вашем случае класс (без объединения) имеет неявно объявленный по умолчанию конструктор без параметров по умолчанию (12.1p5), который не удаляется и является тривиальным (там же). Таким образом, применяется вторая пуля 8.5p8:

- если T является (возможно, cv-квалифицированным) типом класса без объединения без предоставленного пользователем или удаленного конструктора по умолчанию, то объект инициализируется нулями и, если T имеет нетривиальный конструктор по умолчанию, инициализируется по умолчанию;

Таким образом, A должен быть инициализирован нулем, а программа должна напечатать 0.

По следующей программе:

struct A { int get() { return i; } private: int i; };
#include <iostream>
int main() {
    char c[sizeof(A)];
    new (c) int{42};
    std::cout << (new (c) A{})->get() << '\n';
}

gcc-4.7.2 правильно выводит 0; gcc-4.6.3 неправильно выводит 42; clang-3.0 совершенно сходит с ума и выводит мусор (например, 574874232).

person ecatmur    schedule 17.12.2012
comment
С каких это пор нулевая инициализация или инициализация класса по умолчанию затрагивают любые другие неинициализированные члены? - person Lightness Races in Orbit; 05.10.2015
comment
@LightnessRacesinOrbit, по крайней мере, начиная с C++11 [dcl.init] /5: [...] — если T является (возможно, cv-квалифицированным) типом класса без объединения, каждый нестатический член данных, и каждый подобъект базового класса инициализируется нулями, а заполнение инициализируется нулевыми битами; [...] - person ecatmur; 05.10.2015