What do the following phrases mean in C++:
zero-initialization,
default-initialization, and
value-initialization
What should a C++ developer know about them?
What do the following phrases mean in C++:
zero-initialization,
default-initialization, and
value-initialization
What should a C++ developer know about them?
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;
}
int
, but m()
on the third line value initializes m. Important if you change int m;
to B m;
. :) –
Cellini 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 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 value-initialization
and default-initialization
. –
Monandrous 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-initializedA 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.
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;
}
int
, but m()
on the third line value initializes m. Important if you change int m;
to B m;
. :) –
Cellini 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 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 value-initialization
and default-initialization
. –
Monandrous © 2022 - 2024 — McMap. All rights reserved.