I have the following
char mem_pool[1024*1024*64];
int main() {
// ...
}
I'm trying to get a thorough understanding how will mem_pool be initialized. After a lot of search my conclusions are :
it's a static initialization (not as in static the keyword, but as in "run before the program does - during static initialization phase")
it will run in 2 phases : zero initialization and default initialization (the second phase won't do anytning)
it's an array of PODs so the default initialization for every element should apply, but due to the previous 2 points we won't have an array of indeterminable values (as we would with a char ar[N] in a function scope) but an array of zeroes.
Could someone help me dissambiguate what's guaranteed by the language and correct me if I'm wrong ?
I also thought of doing any of the following
char mem_pool[1024*1024*64] {};
char mem_pool[1024*1024*64] = "";
I suspect it's a better/recommended practice, but for now I need to understand my initial question.
Your understanding is correct.
The array's elements will all be zero-initialised, because the array has static storage duration:
[C++11: 3.6.2/2]: Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place. [..]
[C++11: 8.5/5]: To zero-initialize an object or reference of type T means:
if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
If it did not have static storage duration, the elements would all have indeterminate values:
[C++11: 8.5/11]: If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [..]
[C++11: 8.5/6]: To default-initialize an object of type T means:
if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
if T is an array type, each element is default-initialized;
otherwise, no initialization is performed.
Related
Is the following code valid, e.g. doesn't bring undefined behaviour?
struct S
{
int i = s.i;
static S s;
};
S S::s;
int main()
{
S a; // a.i = 0
S::s.i = 42;
S b; // b.i = 42
}
As far as I know all variables with static storage duration are zero initialized. Hence s.i is 0 on S::s creation, and all is good. But maybe I'm missing something.
I would argue it's well defined.
[class.static.data]/6
Static data members are initialized and destroyed exactly like
non-local variables.
[basic.start.static]/2 (emphasis mine)
A constant initializer for a variable or temporary object o is an
initializer whose full-expression is a constant expression, except
that if o is an object, such an initializer may also invoke constexpr
constructors for o and its subobjects even if those objects are of
non-literal class types. [ Note: Such a class may have a non-trivial
destructor. — end note ] Constant initialization is performed if a
variable or temporary object with static or thread storage duration is
initialized by a constant initializer for the entity. If constant
initialization is not performed, a variable with static storage
duration or thread storage duration is zero-initialized. Together,
zero-initialization and constant initialization are called static
initialization; all other initialization is dynamic initialization.
All static initialization strongly happens before ([intro.races]) any dynamic initialization. [ Note: The dynamic initialization of
non-local variables is described in [basic.start.dynamic]; that of
local static variables is described in [stmt.dcl]. — end note ]
[dcl.init]/6 (emphasis mine)
To zero-initialize an object or reference of type T means:
if T is a scalar type, the object is initialized to the value obtained by converting the integer literal 0 (zero) to T;
if T is a (possibly cv-qualified) non-union class type, each non-static data member, each non-virtual base class subobject, and, if
the object is not a base class subobject, each virtual base class
subobject is zero-initialized and padding is initialized to zero bits;
if T is a (possibly cv-qualified) union type, the object's first non-static named data member is zero-initialized and padding is
initialized to zero bits;
if T is an array type, each element is zero-initialized;
if T is a reference type, no initialization is performed.
Because int i = s.i; means s.i goes through dynamic initialization, it's guaranteed to be zero initialized beforehand. So when it'll be used to initialize itself later, it's value won't be indeterminate. A 0 is to be expected.
You are missing something. Variables with static storage duration are zeroed, and then their constructor is called.
What I can't quite tell is whether the initialization of S.i with the value of S.i is undefined behaviour (because S.i is not initialized at this point) or not (because it must be zero).
Edit: The code in Defect Report 2026 is very similar in effect to this, and is declared to be ill-formed (which means the compiler must error). My suspicion is that the intention of the committee is that the OP's code is undefined behaviour.
Edit 2: The above DR refers to constexpr values. That probably changes things enough that is irrelevant.
Having said that: if you are relying on very careful reading of the standard to make your code legal, you are relying on the compiler author to have read it as carefully. You may be right, but that doesn't help in the short-term if the compiler author has misread and implemented something else (although hopefully, they will eventually fix the bug).
Consider following program:
#include <iostream>
struct Test
{
int a;
};
int main()
{
Test t=Test();
std::cout<<t.a<<'\n';
}
Test t=Test(); value initializes a temporary & copy initializes it. (most compilers optimize out the copy operation (Source: value initialization)). But value initialization is introduced by C++03. What happens in C++98 when Test t=Test(); is executed? Is it guaranteed that I will get 0 as an output (value of t.a in this case) on any C++98 compiler? . Is it default initialization being performed in C++98?
C++ standard (1998)
[dcl.fct.def]
7 An object whose initializer is an empty set of parentheses, i.e., (), shall be default-initialized.
[dcl.init]
5 To zero-initialize storage for an object of type T means:
— if T is a scalar type (3.9), the storage is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, the storage for each nonstatic data member and each base-class subobject is zero-initialized;
— if T is a union type, the storage for its first data member 89) is zero-initialized;
— if T is an array type, the storage for each element is zero-initialized;
— if T is a reference type, no initialization is performed.
To default-initialize an object of type T means:
— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the storage for the object is zero-initialized.
It appears that the temporary is default initialized, which means zero initialization for a POD type (which Test is) and therefore t.a == 0 is guaranteed.
Since C++03 this is value initialization and same guarantee remains.
It appears that the addition of value initialization and re-definition of default initialization in C++03, was to allow not zero-initializing scalars and POD types (in some contexts).
Is the behavior below well-defined?
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int a[10] = {1, 2, 3, 4, 5};
for(const auto &i: a)
cout << i << endl;
return 0;
}
Output:
1
2
3
4
5
0
0
0
0
0
Yes, excess elements are initialized to "zero" (integers to 0, floating-point numbers to 0.0, pointers to NULL).
More precisely, the C standard requires that they are initialized as if they had static storage duration:
C99 Standard, paragraph 6.7.8.21:
If there are fewer initializers in a brace-enclosed list than there are elements or members
of an aggregate, or fewer characters in a string literal used to initialize an array of known
size than there are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage duration.
6.7.8.10:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static storage duration is not initialized explicitly,
then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.
Damn, it's C++. (Nobody except #yuan realized this, thanks!)
So paragraph 8.5.1.7 in C++11:
To value-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the
default constructor for T is called (and the initialization is ill-formed if T has no accessible default
constructor);
— if T is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object
is zero-initialized and, if T’s implicitly-declared default constructor is non-trivial, that constructor is
called.
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized.
8.5.1.5:
To zero-initialize an object or reference of type T means:
— if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression,
converted to T;
103
— if T is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class
subobject is zero-initialized and padding is initialized to zero bits;
— if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zeroinitialized and padding is initialized to zero bits;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
Does int a = int(); necessarily give me a zero?
How about if int is replaced by char, double, bool or pointer type?
Where is this specified in the language standard, please?
Does int a = int(); necessarily give me a zero?
Yes, the standard guarantees that it gives you zero.
This is known as Value Initialization. For the type int, Value Initialization basically ends up being an Zero Initialization.
Where is this specified in the language standard, please?
The rules are clearly specified in the standard in section 8.5.
I will quote the relevant ones to the Q here:
C++03: 8.5 Initializers
Para 7:
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
Value Initialization & Zero Initialization are defined in 8.5 Para 5 as:
To value-initialize an object of type T means:
— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default
constructor for T is called (and the initialization is ill-formed if T has no accessible
default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static
data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized
To zero-initialize an object of type T means:
— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject
is zero-initialized;
— if T is a union type, the object’s first named data member is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.
Note: The bold texts are emphasized by me.
Yes, any built-in type is always initialized to zero when default-initialized. Keep in mind that in most scenarios a built-in type is not default initialized so this won't necessarily print out 0:
int i;
std::cout << i << "\n";
WCHAR wszFoo[CONSTANT_BAR] = {0};
I've never seen something like {0} used in C++ as part of the language. And I have no idea how to search for a question like this online. What is it?
See array initialization.
Missing initialization values use zero
If an explicit array size is
specified, but an shorter
initiliazation list is specified, the
unspecified elements are set to zero.
float pressure[10] = {2.101, 2.32,
1.44};
This not only initializes the first
three values, but all remaining
elements are set to 0.0. To initialize
an array to all zeros, initialize only
the first value.
$8.5.1/7 -
"If there are fewer initializers in
the list than there are members in the
aggregate, then each member not
explicitly initialized shall be
value-initialized (8.5)."
All this means, is that there is an explict request to initialize first element to 0. Since initializers are not specified for the remaining elements, they are value-initialized. This in case of WCHARs means are initialized to 0.
What does value initialized means? Here is what the Standard says in $8.5 (italics are mine)
To value-initialize an object of type
T means:
— if T is a class type
(clause 9) with a user-declared
constructor (12.1), then the default
constructor for T is called (and the
initialization is ill-formed if T has
no accessible default constructor);
—
if T is a non-union class type without
a user-declared constructor, then
every non-static data member and
base-class component of T is
value-initialized;
— if T is an array
type, then each element is
value-initialized;
— otherwise, the
object is zero-initialized <------
WCHAR will fit here
To zero-initialize an object of type T
means:
— if T is a scalar type (3.9),
the object is set to the value of 0
(zero) converted to T; <------ WCHAR
will fit here
— if T is a non-union
class type, each nonstatic data member
and each base-class subobject is
zeroinitialized;
— if T is a union
type, the object’s first named data
member89) is zero-initialized;
— if T
is an array type, each element is
zero-initialized;
— if T is a
reference type, no initialization is
performed.
It's initializing an array.
float p1[1000]; // No intitialization.
float p2[1000] = {0.0}; // All 1000 values initialized to zero.
More here: C++ Notes: Array Initialization
It means initialize all elements of wszFoo to zero.