23

I know some POD variables are initialized by default to a meaningful value but others are not. (POD types include int, float, pointers, unions, arrays of POD types, structs of POD types, etc.)

How does scope and storage class affect initialization of POD types?

Specifically, which of the following will be initialized implicitly to a known value (e.g., 0 for integer types) (i.e., value initialization) and which are defined with an indeterminate value (i.e., default initialization):

  • Local variables with automatic storage
  • Static local variables
  • Static global variables
  • External variables
  • Variables allocated with new
  • POD members of a class (without explicit initialization in a constructor)

I know there are existing questions relating to some of these situations, but none comprehensive (they only address specific situations).

Hari
  • 1,561
  • 4
  • 17
  • 26
Daniel Hanrahan
  • 4,801
  • 7
  • 31
  • 44
  • 2
    What do you mean by "modifier"? Do not confuse the `static` storage class specifier with static storage duration, the former has no effect on initialization, the latter does. – Jonathan Wakely Mar 04 '13 at 22:37
  • 1
    Yeah I meant storage class. Fixed. – Daniel Hanrahan Mar 04 '13 at 22:39
  • @JonathanWakely, I think you confused _linkage_ with _storage duration_ back then _(hehh, exactly 10 years ago today, happy decaversary! :) )_. From cppreference's **[Storage class specifiers](https://en.cppreference.com/w/cpp/language/storage_duration)** page _(note that the URL itself already says: "storage_duration"...)_: "**static - static or thread storage duration** and internal linkage" I mean, no wonder, the entire C++ standard is a growing black hole of confusing definitions, _especially about initialization_... :) – Sz. Mar 04 '23 at 14:00

2 Answers2

26

Local variables with automatic storage duration are not being initialized automatically. Since using uninitialized variables produces undefined behavior, it is a good practice to explicitly initialize your variables even when it's redundant.

About POD types that are being zero-initialized, C++03 standard 3.6.2 Initialization of non-local objects states:

§1 Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.

So it's guaranteed by standard that POD types with static storage duration (whatever their scope is) will be zero-initialized.

POD members of a class (without explicit initialization in a constructor)

This situation is described in 12.6.2 Initializing bases and members, that states (selected parts):

If a given nonstatic data member or base class is not named by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then:

— If the entity is a nonstatic data member..., and the entity class is a non-POD class, the entity is default-initialized (8.5)...

Otherwise, the entity is not initialized...

After the call to a constructor for class X has completed, if a member of X is neither specified in the constructor’s mem-initializers, nor default-initialized, nor value-initialized, nor given a value during execution of the body of the constructor, the member has indeterminate value.

Example:

class C
{
public:
    C(int x, int z) : x(x), z(z) { }
    int x, y, z;
};

int main(void)
{
    C* c = new C(1,3);
    std::cout << c->y; // value of y is undetermined !!!
}
LihO
  • 41,190
  • 11
  • 99
  • 167
  • 1
    "using uninitialized variables produces undefined behavior" might be a little too strong. It's reading their values that's UB. If you assign a value (maybe much later than the object's creation) before reading the variable, you're good. – Spencer May 18 '22 at 12:47
13

If we're only talking about PODs then only local and global statics and external variables because they have to be defined somewhere.

PODs allocated with new are also initialized sometimes - if you make the initialization explicit:

int* x = new int();

will create an int initialized to 0 with x pointing to it, whereas

int* x = new int;

will have x point to an uninitialized int.

Sometimes - POD class members - they can be initialized explicitly (without being in a constructor):

struct X
{
   int x;
};

X x;        //x.x is not initialized
X y = X();  //y.x is 0
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • I'm curious about the last case: what if there is a constructor, but it does not initialize `x`. Will `x` be initialized to 0 with `X()`? i.e. do you need to initialize all POD types within a constructor if you have one? – Daniel Hanrahan Mar 04 '13 at 22:48
  • @QuasarDonkey: Check my answer, the example I added at the bottom. – LihO Mar 04 '13 at 23:09