What do the following phrases mean in C++: zero-, default- and value-initialization?
Asked Answered
D

2

212

What do the following phrases mean in C++:

  • zero-initialization,

  • default-initialization, and

  • value-initialization

What should a C++ developer know about them?

Doubledealing answered 23/10, 2009 at 13:14 Comment(3)
This is related to (but not identical to) stackoverflow.com/questions/620137/…Khalid
There's more! The complete list of initializations: Value, direct, copy, list (C++11 new intro), aggregate, reference, zero, constant and default; en.cppreference.com/w/cpp/language/initialization lists all of them with examples :)Flatworm
@Flatworm This is good, thank you! I was hoping somebody would talk about newer standards!Occultation
E
67

One thing to realize is that 'value-initialization' is new with the C++ 2003 standard - it doesn't exist in the original 1998 standard (I think it might be the only difference that's more than a clarification). See Kirill V. Lyadvinsky's answer for the definitions straight from the standard.

See this previous answer about the behavior of operator new for details on the the different behavior of these type of initialization and when they kick in (and when they differ from c++98 to C++03):

The main point of the answer is:

Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD, or if it's a class that contains POD members and is using a compiler-generated default constructor.

  • In C++1998 there are 2 types of initialization: zero and default
  • In C++2003 a 3rd type of initialization, value initialization was added.

To say they least, it's rather complex and when the different methods kick in are subtle.

One thing to certainly be aware of is that MSVC follows the C++98 rules, even in VS 2008 (VC 9 or cl.exe version 15.x).

The following snippet shows that MSVC and Digital Mars follow C++98 rules, while GCC 3.4.5 and Comeau follow the C++03 rules:

#include <cstdio>
#include <cstring>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    std::printf( "m  is %d\n", pB->m);
    return 0;
}
Eterne answered 23/10, 2009 at 13:48 Comment(8)
Not that it matters for int, but m() on the third line value initializes m. Important if you change int m; to B m;. :)Cellini
Right - A and C aren't used in this example (they're carried over from the other linked answer). Even though C++98 and C++03 use different terminology when describing how A and C are constructed, the result is the same in both standards. Only struct B results in different behavior.Eterne
what i meant is that if you change C to struct C { C() : m() {}; ~C(); B m; };, then you will have m.m be 0. But if it would default-initialise m like you say C++03 does, then m.m would be not initialized like in C++98.Cellini
Additional interesting comments on MSVC handling of this feature: stackoverflow.com/questions/3931312/…Gaskell
Which initialization takes place when you declare your type as a local variable, i.e. at the stack?Kurbash
Here's a great reference on value-initialization and default-initialization.Monandrous
g++ 4.4.7 20120313 for Red Hat 4.4.7-18 initializes m to 0 with your example (compiling with -std=c++98).Yon
g++ 10.2.0 for Ubuntu initializes m to 0 with your example (compiling with -std=c++98) as wellNievesniflheim
A
91

C++03 Standard 8.5/5:

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

A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed. If T is a cv-qualified type, the cv-unqualified version of T is used for these definitions of zero-initialization, default-initialization, and value-initialization.

Ahrens answered 23/10, 2009 at 13:20 Comment(3)
This might be outdated for C++11. cppreference.com states that default initialization does not zero-initialize members (only value initialization does).Monandrous
@android raises an important point, which I don't see answered elsewhere, so I've made a new question. stackoverflow.com/questions/22233148/…Lap
Exactly zero-intialization in case of default-initialization does not happen. Value remains indeterminate.Cento
E
67

One thing to realize is that 'value-initialization' is new with the C++ 2003 standard - it doesn't exist in the original 1998 standard (I think it might be the only difference that's more than a clarification). See Kirill V. Lyadvinsky's answer for the definitions straight from the standard.

See this previous answer about the behavior of operator new for details on the the different behavior of these type of initialization and when they kick in (and when they differ from c++98 to C++03):

The main point of the answer is:

Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD, or if it's a class that contains POD members and is using a compiler-generated default constructor.

  • In C++1998 there are 2 types of initialization: zero and default
  • In C++2003 a 3rd type of initialization, value initialization was added.

To say they least, it's rather complex and when the different methods kick in are subtle.

One thing to certainly be aware of is that MSVC follows the C++98 rules, even in VS 2008 (VC 9 or cl.exe version 15.x).

The following snippet shows that MSVC and Digital Mars follow C++98 rules, while GCC 3.4.5 and Comeau follow the C++03 rules:

#include <cstdio>
#include <cstring>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    std::printf( "m  is %d\n", pB->m);
    return 0;
}
Eterne answered 23/10, 2009 at 13:48 Comment(8)
Not that it matters for int, but m() on the third line value initializes m. Important if you change int m; to B m;. :)Cellini
Right - A and C aren't used in this example (they're carried over from the other linked answer). Even though C++98 and C++03 use different terminology when describing how A and C are constructed, the result is the same in both standards. Only struct B results in different behavior.Eterne
what i meant is that if you change C to struct C { C() : m() {}; ~C(); B m; };, then you will have m.m be 0. But if it would default-initialise m like you say C++03 does, then m.m would be not initialized like in C++98.Cellini
Additional interesting comments on MSVC handling of this feature: stackoverflow.com/questions/3931312/…Gaskell
Which initialization takes place when you declare your type as a local variable, i.e. at the stack?Kurbash
Here's a great reference on value-initialization and default-initialization.Monandrous
g++ 4.4.7 20120313 for Red Hat 4.4.7-18 initializes m to 0 with your example (compiling with -std=c++98).Yon
g++ 10.2.0 for Ubuntu initializes m to 0 with your example (compiling with -std=c++98) as wellNievesniflheim

© 2022 - 2024 — McMap. All rights reserved.