Difference between revisions of "cpp/language/zero initialization"
("T t = {};" is not a zero-initialization, it is a copy-list-initialization with an empty braced-init-list) |
Andreas Krug (Talk | contribs) m (headers sorted) |
||
(15 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
− | {{title|Zero initialization}} | + | {{title|Zero-initialization}} |
{{cpp/language/initialization/navbar}} | {{cpp/language/initialization/navbar}} | ||
− | Sets the initial value of an object to zero | + | Sets the initial value of an object to zero. |
===Syntax=== | ===Syntax=== | ||
+ | Note that this is not the syntax for zero-initialization, which does not have a dedicated syntax in the language. These are examples of other types of initializations, which might perform zero-initialization. | ||
{{sdsc begin}} | {{sdsc begin}} | ||
− | {{sdsc | num=1 | {{ttb|static}} {{spar|T}} {{spar| object}} {{ttb|;}}}} | + | {{sdsc|num=1|{{ttb|static}} {{spar|T}} {{spar|object}} {{ttb|;}}}} |
− | {{sdsc | num=2 | | + | {{sdsc|num=2| |
− | {{spar|T}} {{ttb| | + | {{spar|T}} {{ttb|()}} {{ttb|;}} |
+ | |||
+ | {{spar|T}} {{spar|t}} {{ttb|{{=}}}} {{ttb|{}<!-- -->}} {{ttb|;}} | ||
+ | |||
+ | {{spar|T}} {{ttb|{}<!-- -->}} {{ttb|;}} {{mark since c++11}} | ||
}} | }} | ||
− | {{sdsc | num=3 | {{spar|CharT}} {{spar|array}} {{ttb|[}} {{spar|n}} {{ttb|]}} {{ttb|{{=}}}} {{ttb|"";}}}} | + | {{sdsc|num=3|{{spar|CharT}} {{spar|array}} {{ttb|[}} {{spar|n}} {{ttb|]}} {{ttb|{{=}}}} {{ttb|"}} {{spar|short-sequence}} {{ttb|";}}}} |
{{sdsc end}} | {{sdsc end}} | ||
===Explanation=== | ===Explanation=== | ||
+ | Zero-initialization is performed in the following situations: | ||
+ | @1@ For every named variable with static{{rev inl|since=c++11| or thread-local}} {{rlp|storage duration}} that is not subject to {{rlp|constant initialization}}, before any other initialization. | ||
+ | @2@ As part of {{rlp|value initialization|value-initialization}} sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of {{rlp|aggregate initialization|aggregates}} for which no initializers are provided. | ||
+ | @3@ When an array of any {{rlp|types#Character types|character type}} is {{rlp|aggregate initialization#Character arrays|initialized with a string literal}} that is too short, the remainder of the array is zero-initialized. | ||
− | + | The effects of zero-initialization are: | |
− | + | * If {{tt|T}} is a [[cpp/named req/ScalarType|scalar type]], the object is initialized to the value obtained by {{rlp|explicit cast|explicitly converting}} the integer literal {{c|0}} (zero) to {{tt|T}}. | |
− | + | * If {{tt|T}} is a non-union class type: | |
− | + | :* all {{rlp|object#Object representation and value representation|padding bits}} are initialized to zero bits, | |
− | + | :* each non-static {{rlp|data members|data member}} is zero-initialized, | |
− | + | :* each non-virtual base class {{rlp|object#Subobjects|subobject}} is zero-initialized, and | |
− | + | :* if the object is not a base class subobject, each {{rlp|derived class#Virtual base classes|virtual base class}} subobject is zero-initialized. | |
− | + | * If {{tt|T}} is a union type: | |
− | + | :* all padding bits are initialized to zero bits, and | |
− | * If {{tt|T}} is | + | :* the object’s first non-static named data member is zero-initialized. |
− | + | * If {{tt|T}} is array type, each element is zero-initialized. | |
− | * If {{tt|T}} is a union type, the first non-static named data member is zero-initialized | + | |
− | + | ||
− | * If {{tt|T}} is array type, each element is zero-initialized | + | |
− | + | ||
* If {{tt|T}} is reference type, nothing is done. | * If {{tt|T}} is reference type, nothing is done. | ||
===Notes=== | ===Notes=== | ||
− | As described in | + | As described in {{rlp|initialization#Non-local variables|non-local initialization}}, static{{rev inl|since=c++11| and thread-local}} variables that aren't constant-initialized are zero-initialized before any other initialization takes place. If the definition of a non-class non-local variable has no initializer, then default initialization does nothing, leaving the result of the earlier zero-initialization unmodified. |
A zero-initialized pointer is the null pointer value of its type, even if the value of the null pointer is not integral zero. | A zero-initialized pointer is the null pointer value of its type, even if the value of the null pointer is not integral zero. | ||
===Example=== | ===Example=== | ||
− | |||
{{example | {{example | ||
− | + | |code= | |
− | + | ||
− | + | ||
#include <iostream> | #include <iostream> | ||
+ | #include <string> | ||
− | struct A { | + | struct A |
− | int a,b,c; | + | { |
+ | int a, b, c; | ||
}; | }; | ||
− | double f[3]; // zero-initialized to three 0.0's | + | double f[3]; // zero-initialized to three 0.0's |
− | int* p; | + | |
− | std::string s; // zero-initialized to indeterminate value | + | int* p; // zero-initialized to null pointer value |
− | // | + | // (even if the value is not integral 0) |
− | int main(int argc, char* | + | |
+ | std::string s; // zero-initialized to indeterminate value, then | ||
+ | // default-initialized to "" by the std::string default constructor | ||
+ | |||
+ | int main(int argc, char*[]) | ||
{ | { | ||
− | |||
− | |||
− | |||
− | |||
delete p; // safe to delete a null pointer | delete p; // safe to delete a null pointer | ||
+ | |||
+ | static int n = argc; // zero-initialized to 0 then copy-initialized to argc | ||
+ | std::cout << "n = " << n << '\n'; | ||
+ | |||
+ | A a = A(); // the effect is same as: A a{}; or A a = {}; | ||
+ | std::cout << "a = {" << a.a << ' ' << a.b << ' ' << a.c << "}\n"; | ||
} | } | ||
− | + | |p=true <!-- argc --> | |
+ | |output= | ||
+ | n = 1 | ||
+ | a = {0 0 0} | ||
}} | }} | ||
===Defect reports=== | ===Defect reports=== | ||
{{dr list begin}} | {{dr list begin}} | ||
− | {{dr list item|wg=cwg|dr=2026|std=C++ | + | {{dr list item|wg=cwg|dr=277|std=C++98|before=pointers might be initialized with a non-constant<br>expression of value 0, which is not a null pointer constant|after=must initialize with an integral<br>constant expression of value 0}} |
+ | {{dr list item|wg=cwg|dr=694|std=C++98|before=zero-initialization for class types ignored padding|after=padding is initialized to zero bits}} | ||
+ | {{dr list item|wg=cwg|dr=903|std=C++98|before=zero-initialization for scalar types set the initial value to the value<br>converted from an integral constant expression with value 0|after=the object is initialized to the value<br>converted from the integer literal {{c|0}}}} | ||
+ | {{dr list item|wg=cwg|dr=2026|std=C++98|before=zero-initialization was specified to always<br>occur first, even before constant initialization|after=no zero-initialization if<br>constant initialization applies}} | ||
+ | {{dr list item|wg=cwg|dr=2196|std=C++98|before=zero-initialization for class types ignored base class subobjects|after=they are also zero-initialized}} | ||
+ | {{dr list item|wg=cwg|dr=2253|std=C++98|before=it was unclear whether zero-initialization<br>applies to unnamed bit-fields|after=it applies (all padding bits<br>are initialized to zero bits)}} | ||
{{dr list end}} | {{dr list end}} | ||
===See also=== | ===See also=== | ||
− | * {{rlp | | + | * {{rlp|constructor}} |
− | + | * {{rlp|copy assignment}} | |
− | * {{rlp | copy assignment | + | * {{rlp|default constructor}} |
− | + | * {{rlp|initialization}} | |
− | * {{rlp | default constructor | + | ** {{rlp|aggregate initialization}} |
− | + | ** {{rlp|constant initialization}} | |
− | + | ** {{rlp|copy initialization}} | |
− | * {{rlp | initialization}} | + | ** {{rlp|default initialization}} |
− | ** {{rlp | aggregate initialization}} | + | ** {{rlp|direct initialization}} |
− | ** {{rlp | constant initialization}} | + | ** {{rlp|list initialization}} |
− | ** {{rlp | copy initialization}} | + | ** {{rlp|value initialization}} |
− | ** {{rlp | default initialization}} | + | * {{rlp|move assignment}} |
− | ** {{rlp | direct initialization}} | + | * {{rlpt|new}} |
− | ** {{rlp | | + | |
− | + | ||
− | + | ||
− | ** {{rlp | value initialization}} | + | |
− | * {{rlp | move assignment}} | + | |
− | * {{ | + | |
− | + | ||
− | + | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Latest revision as of 06:52, 20 May 2023
Sets the initial value of an object to zero.
Contents |
[edit] Syntax
Note that this is not the syntax for zero-initialization, which does not have a dedicated syntax in the language. These are examples of other types of initializations, which might perform zero-initialization.
static T object ;
|
(1) | ||||||||
T () ;
T t T |
(2) | ||||||||
CharT array [ n ] = " short-sequence ";
|
(3) | ||||||||
[edit] Explanation
Zero-initialization is performed in the following situations:
The effects of zero-initialization are:
- If
T
is a scalar type, the object is initialized to the value obtained by explicitly converting the integer literal 0 (zero) toT
. - If
T
is a non-union class type:
- all padding bits are initialized to zero bits,
- each non-static data member is zero-initialized,
- each non-virtual base class subobject is zero-initialized, and
- if the object is not a base class subobject, each virtual base class subobject is zero-initialized.
- If
T
is a union type:
- all padding bits are initialized to zero bits, and
- the object’s first non-static named data member is zero-initialized.
- If
T
is array type, each element is zero-initialized. - If
T
is reference type, nothing is done.
[edit] Notes
As described in non-local initialization, static and thread-local(since C++11) variables that aren't constant-initialized are zero-initialized before any other initialization takes place. If the definition of a non-class non-local variable has no initializer, then default initialization does nothing, leaving the result of the earlier zero-initialization unmodified.
A zero-initialized pointer is the null pointer value of its type, even if the value of the null pointer is not integral zero.
[edit] Example
#include <iostream> #include <string> struct A { int a, b, c; }; double f[3]; // zero-initialized to three 0.0's int* p; // zero-initialized to null pointer value // (even if the value is not integral 0) std::string s; // zero-initialized to indeterminate value, then // default-initialized to "" by the std::string default constructor int main(int argc, char*[]) { delete p; // safe to delete a null pointer static int n = argc; // zero-initialized to 0 then copy-initialized to argc std::cout << "n = " << n << '\n'; A a = A(); // the effect is same as: A a{}; or A a = {}; std::cout << "a = {" << a.a << ' ' << a.b << ' ' << a.c << "}\n"; }
Possible output:
n = 1 a = {0 0 0}
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 277 | C++98 | pointers might be initialized with a non-constant expression of value 0, which is not a null pointer constant |
must initialize with an integral constant expression of value 0 |
CWG 694 | C++98 | zero-initialization for class types ignored padding | padding is initialized to zero bits |
CWG 903 | C++98 | zero-initialization for scalar types set the initial value to the value converted from an integral constant expression with value 0 |
the object is initialized to the value converted from the integer literal 0 |
CWG 2026 | C++98 | zero-initialization was specified to always occur first, even before constant initialization |
no zero-initialization if constant initialization applies |
CWG 2196 | C++98 | zero-initialization for class types ignored base class subobjects | they are also zero-initialized |
CWG 2253 | C++98 | it was unclear whether zero-initialization applies to unnamed bit-fields |
it applies (all padding bits are initialized to zero bits) |