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

Имах някои съмнения, след като обсъдих това с колеги...

Както пита заглавието, кога може да се предположи, че вградените типове ще бъдат инициализирани на 0 вместо на неизвестна стойност?

Различават ли се правилата в различните c++ стандарти?


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 типове да бъдат инициализирани?. Обърнете внимание на автоматично в първото изречение, във всички останали случаи кодът изисква инициализация. (BTW, използвах само синтаксис на C++03, можете да използвате синтаксис за унифицирана инициализация на C++11 вместо скобите) - person David Rodríguez - dribeas; 08.02.2013
comment
Смятате ли, че формулирах този въпрос зле? Надявам се да науча кога моите ints ще бъдат 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:

Всеки обект със статична продължителност на съхранение трябва да бъде инициализиран с нула при стартиране на програмата, преди да се извърши всяка друга инициализация.

Това е същото и в двата стандарта. Единствената разлика е във формулировката на 8.5 §6 на C++98:

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


Пример:

Ето примера, където 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 променлива на средата или по друг начин, ще откриете, че в повечето случаи паметта не се инициализира.

Като правило инициализирайте вашите променливи, тъй като е по-безопасно да програмирате по този начин.

РЕДАКТИРАНЕ: Както беше посочено от Luchian Grigore, променливите за обхват на глобалното/именното пространство са изключение. Те също така често не работят с неинициализирани проверки на променливи поради тази инициализация.

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