Имах някои съмнения, след като обсъдих това с колеги...
Както пита заглавието, кога може да се предположи, че вградените типове ще бъдат инициализирани на 0 вместо на неизвестна стойност?
Различават ли се правилата в различните c++ стандарти?
Имах някои съмнения, след като обсъдих това с колеги...
Както пита заглавието, кога може да се предположи, че вградените типове ще бъдат инициализирани на 0 вместо на неизвестна стойност?
Различават ли се правилата в различните c++ стандарти?
Пълните правила са в [dcl.init] (C++11). За да обобщим: когато в декларация не е предоставен инициализатор, обектът е така нареченият инициализиран по подразбиране. За типове класове това означава, че се извиква конструкторът по подразбиране. За типове, които не са класове, това означава, че не се извършва инициализация.
Въпреки това, [dcl.init] §9 гласи: "Всеки обект със статично съхранение се инициализира с нула при стартиране на програмата, преди да се извърши всяка друга инициализация."
Това означава, че променливи със статична продължителност (като променливи с обхват на пространството от имена) от некласов тип са инициализирани с нула. Други обекти от некласови типове (като локални променливи) не се инициализират.
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
}
int
s ще бъдат 0
, когато кодът не споменава 0
, така да се каже.
- person Drew Dormann; 08.02.2013
int x;
гарантира, че x
е 0, а отговорът на това е само ако x
има статично хранилище. Друг въпрос е, когато декларирам променлива x
от тип int
, как мога да гарантирам, че тя е инициализирана, ако не предоставя изрична стойност? и този отговор съдържа различните синтактични форми, които можете използвайте, за да инициализирате стойността.
- person David Rodríguez - dribeas; 09.02.2013
int x;
, тогава въпросът ми е много често срещан. Подозирам, че трябваше да попитам обратното, Кога се създават имплицитни типове с неизвестна стойност? След това се появява статично хранилище, но вашите точки също и може би повече.
- person Drew Dormann; 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
Не бих предположил, че който и да е имплицитен тип ще бъде инициализиран до 0. Може да откриете, че това е случаят, когато работите вътре в дебъгера и използвате стека/стека за отстраняване на грешки. Когато сте извън програмата за отстраняване на грешки или деактивирате купчината за отстраняване на грешки чрез _NO_DEBUG_HEAP=1 променлива на средата или по друг начин, ще откриете, че в повечето случаи паметта не се инициализира.
Като правило инициализирайте вашите променливи, тъй като е по-безопасно да програмирате по този начин.
РЕДАКТИРАНЕ: Както беше посочено от Luchian Grigore, променливите за обхват на глобалното/именното пространство са изключение. Те също така често не работят с неинициализирани проверки на променливи поради тази инициализация.
vector<int> v(10)
прави 0 инициализира това еint
s. - person Chris Hartman   schedule 09.02.2013