ISO C++03 is about as authoritative as it gets:
A POD-struct is an aggregate class that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-defined copy assignment operator and no user-defined destructor. Similarly, a POD-union is an aggregate union that has no non-static data members of type non-POD-struct, non-POD-union (or array of such types) or reference, and has no user-defined copy assignment operator and no user-defined destructor. A POD class is a class that is either a POD-struct or a POD-union.
Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2), and cv-qualified versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD-struct types, POD-union types (clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types.
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.
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 object is zero-initialized.
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
Every object of static storage duration shall be zero-initialized at program startup before any other initialization takes place. [Note: in some cases, additional initialization is done later.]
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value); if the object or any of its subobjects are of const-qualified type, the program is ill-formed.
For your example, int
is definitely a POD type (it's an arithmetic type), and therefore a local or field of type int
, in the absence of initializer, will have an indeterminate value. For Foo
, this depends on how it is defined - roughly speaking, if it doesn't have a constructor, and all its members are of POD types, then it is itself a POD type, and no initialization takes place either. Otherwise, the default constructor is called. Even then, this doesn't mean that members are initialized - rules are recursive, so POD members of non-POD type won't be initialized unless the constructor of that type specifically does that (in its initializer list).
Static variables and fields will in all cases be zero-initialized. Note that this applies to non-PODs too - meaning that a static variable of a class type is guaranteed to have all fields recursively set to (T)0
even before its constructor runs.
A handy trick to default-initialize any aggregate POD type is to use {}
in initializer - note that it works with structs as well as arrays:
char s[10] = {}; // all elements default-initialized
Foo foo = {}; // all fields recursively default-initialized
int* primes = new (nothrow) int[amount];
is using default-initialization, which for scalars like int
is a noop (i.e. no actual initialization is performed).
If you want explicit initialization, use value-initialization instead:
int* primes = new (nothrow) int[amount]();
From the C++11 standard, §8.5/6:
To default-initialize an object of type T
means:
- if
T
is a (possibly cv-qualified) class type, 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.
If a program calls for the default initialization of an object of a const-qualified type T
, T
shall be a class type with a user-provided default constructor.
§8.5/7:
To value-initialize an object of type T
means:
- if
T
is a (possibly cv-qualified) class type with a user-provided constructor, 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.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc., even if no constructor is invoked for the object’s initialization.
§8.5/6:
To zero-initialize an object or reference of type T
means:
- if
T
is a scalar type, 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.
And finally from §8.5/10:
An object whose initializer is an empty set of parentheses, i.e., ()
, shall be value-initialized.
(All emphasis mine.)
Best Answer
In this declaration
the array
x
has exactly three elements. So accessing memory outside the bounds of the array invokes undefined behavior.That is, this loop
invokes undefined behavior. The memory after the last element of the array can contain anything.
On the other hand, if the array were declared as
that is, with four elements, then the last element of the array that does not have an explicit initializer will be indeed initialized to zero.