Когда неявные типы C++ инициализируются 0?

У меня возникли некоторые сомнения после обсуждения этого с коллегами...

Как следует из заголовка, когда можно предположить, что встроенные типы будут инициализированы 0 вместо неизвестного значения?

Различаются ли правила в стандартах С++?


person Drew Dormann    schedule 08.02.2013    source источник
comment
Связанные stackoverflow.com/questions/6251707/default-initialization-in-c и stackoverflow.com/questions/2417065/ Хотя краткое изложение этих вопросов было бы полезно.   -  person pmr    schedule 08.02.2013
comment
@pmr хорошие ссылки! Я прочитал вторую, прежде чем опубликовать это. В настоящее время ни в одном из ответов не упоминаются случаи там. Согласен, краткое изложение было бы неплохо.   -  person Drew Dormann    schedule 08.02.2013
comment
Дальнейшие ответы вполне могут добавить объяснение того, почему vector<int> v(10) действительно 0 инициализирует его ints.   -  person Chris Hartman    schedule 09.02.2013


Ответы (4)


Полные правила находятся в [dcl.init] (C++11). Подводя итог: когда в объявлении не указан инициализатор, объект является так называемым инициализированным по умолчанию. Для типов классов это означает, что вызывается конструктор по умолчанию. Для неклассовых типов это означает, что инициализация не выполняется.

Однако в [dcl.init] §9 говорится: «Каждый объект статической продолжительности хранения инициализируется нулями при запуске программы до того, как произойдет любая другая инициализация».

Это означает, что переменные статической длительности (например, переменные области видимости пространства имен) неклассового типа инициализируются нулями. Другие объекты неклассовых типов (например, локальные переменные) не инициализируются.

person Angew is no longer proud of SO    schedule 08.02.2013
comment
Я мог бы добавить, что сгенерированный компилятором конструктор по умолчанию также фактически не инициализирует какие-либо переменные-члены, не относящиеся к классу. Все, что он будет делать, это вызывать конструкторы для членов типа класса. - person ; 08.02.2013
comment
@DrewDormann Я думаю, вы имели в виду int x = int(); Да, это действительно будет инициализировано до 0. Обратите внимание, что в моем ответе говорится, что инициализатор не указан. Если вы его предоставите, он, конечно же, будет им инициализирован. - person Angew is no longer proud of SO; 08.02.2013

Вместо того, чтобы отвечать на точный вопрос, который вы публикуете, на который уже был дан ответ: только объекты POD со статическим хранилищем будут автоматически инициализированы до 0, я попытаюсь предоставить фрагменты кода, чтобы заставить компилятор инициализировать участники для вас:

struct POD {
   int    a;
   double b; //...
};
// namespace level:
POD p;
void f() {
   POD n1;                  // uninitialized
   POD p1 = {};
   POD p2 = POD();
   POD* n2 = new POD;       // uninitialized
   POD* pp1 = new POD();
   delete n2; delete pp1;
}

В приведенных выше примерах не будут инициализированы только те, которые отмечены как «неинициализированные». Обратите внимание, что это относится к тому, что требует стандарт, ваш пробег будет варьироваться в зависимости от разных компиляторов. В частности, у VS есть некоторые проблемы с T t = T(); и T* p = new T()' в некоторых сценариях (IIRC, когда тип T не является POD, но не имеет предоставленного пользователем конструктора по умолчанию, компилятор не сможет инициализировать подобъекты POD:

struct T {
   std::string s;
   int         i;
};
void f() {
   T t = T();    // t.i == 0 according to the standard
}
person David Rodríguez - dribeas    schedule 08.02.2013
comment
Спасибо, но меня смущает ваш ответ - только POD со статическим хранилищем, но похоже, что вы приводите примеры, которые не являются статическим хранилищем. - person Drew Dormann; 08.02.2013
comment
@DrewDormann: Вот почему я ответил на другой вопрос что вы можете сделать, чтобы ваши типы POD были инициализированы?. Обратите внимание на автоматически в первом предложении, во всех остальных случаях код запрашивает инициализацию. (Кстати, я использовал только синтаксис С++ 03, вы можете использовать единый синтаксис инициализации С++ 11 вместо скобок) - person David Rodríguez - dribeas; 08.02.2013
comment
Как вы думаете, я плохо сформулировал этот вопрос? Я надеюсь узнать, когда мои int станут 0, если в коде, так сказать, не упоминается 0. - person Drew Dormann; 08.02.2013
comment
...или, другими словами, на какой вопрос вы только что ответили? - person Drew Dormann; 08.02.2013
comment
@DrewDormann: Насколько я понимаю ваш вопрос, когда/ли: int x; гарантирует, что x равно 0, и ответ на этот вопрос только если x имеет статическое хранилище. Другой вопрос: при объявлении переменной x типа int как я могу убедиться, что она инициализирована, если я не укажу явное значение?, и этот ответ содержит различные формы синтаксиса, которые вы можете используйте для инициализации значения. - person David Rodríguez - dribeas; 09.02.2013
comment
Спасибо за ответ. По крайней мере, я лучше понимаю, почему моя формулировка пошла не так. Если вы предполагаете только синтаксис int x;, то мой вопрос очень распространен. Я подозреваю, что мне следовало спросить об обратном: Когда создаются неявные типы с неизвестным значением? Тогда появляется статическое хранилище, но то же самое будет и с вашими точками, а возможно, и с другими. - person Drew Dormann; 09.02.2013
comment
@DrewDormann: объекты со статической продолжительностью хранения будут иметь четко определенное значение во всех программах. Это для других объектов, где есть варианты. - person David Rodríguez - dribeas; 09.02.2013

Теория:

В соответствии со стандартами C++98 и C++03:

3.6.2 Инициализация нелокальных объектов, §1:

Объекты со статической продолжительностью хранения (3.7.1) должны быть инициализированы нулями (8.5) до того, как произойдет любая другая инициализация.

3.7.1 Длительность статического хранения, §1:

Все объекты, которые не имеют динамического срока хранения и не являются локальными, имеют статический срок хранения.

3.7.1 Длительность статического хранения, §3:

Ключевое слово static можно использовать для объявления локальной переменной со статической продолжительностью хранения.

А также Инициализаторы 8.5, §6:

Каждый объект статической длительности хранения должен быть инициализирован нулями при запуске программы, прежде чем произойдет любая другая инициализация.

Это то же самое в обоих стандартах. Единственное отличие заключается в формулировке C++98 8.5 §6:

Память, занятая любым объектом статической длительности хранения, должна быть инициализирована нулями при запуске программы, прежде чем произойдет любая другая инициализация.


Пример:

Вот пример, где x и y и имеют статическую продолжительность хранения, поэтому стандарт гарантирует, что они оба будут инициализированы нулями при запуске программы. Обратите внимание, что существуют также объекты POD a и b, объявленные таким же образом, поэтому они имеют статическую продолжительность хранения, а это означает, что их элементы (i и d) также будут инициализированы нулями:

struct POD {
    int i;
    double d;
};

int x;
POD a;

int foo() {
    static int y;
    return y;
}

int main() {
    static POD b;
    std::cout << "x   = " << x      << std::endl;
    std::cout << "y   = " << foo()  << std::endl;
    std::cout << "a.i = " << a.i    << std::endl;
    std::cout << "b.d = " << b.d    << std::endl;
}

Вывод этого примера, конечно, тогда:

x   = 0
y   = 0
a.i = 0
b.d = 0
person LihO    schedule 08.02.2013

Я бы не стал предполагать, что какой-либо неявный тип будет инициализирован 0. Вы можете обнаружить, что это тот случай, когда вы работаете внутри отладчика и используете отладочную кучу/стек. Когда вы находитесь вне отладчика или отключаете отладочную кучу с помощью переменной среды _NO_DEBUG_HEAP=1, или иным образом, вы обнаружите, что в большинстве случаев память не инициализируется.

Как правило, инициализируйте свои переменные, так как программировать таким образом безопаснее.

РЕДАКТИРОВАТЬ: Как указал Лучиан Григоре, глобальные переменные области видимости/пространства имен являются исключением. Они также часто не работают с проверками неинициализированных переменных из-за этой инициализации.

person Crog    schedule 08.02.2013
comment
переменные в пространстве имен? - person Luchian Grigore; 08.02.2013