Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are members of a built-in type ever default-initialised?

I recently ran into a problem with one of my classes because I hadn't set a pointer to NULL in my constructor initialiser list and so it contained rubbish when I ran the program.

However, whilst I know that instances of a built-in type declared on the stack but not initialised will contain random values, I was pretty sure I'd read somewhere that as class members not placed explicitly in the constructor initialiser list would have their default constructors called, for built-in types this would occur too, inserting code like a pseudo-constructor that will on most platforms, set them to zero I also thought I'd read in 'Thinking in C++' somewhere that under certain circumstances before an object is constructed its memory will be zeroed-out, however I appear to be wrong on both occasions.

Please could anyone confirm for me,
a) Does initialisation of members of a built-in type have anything to do with whether a user-defined constructor is defined or not,
b) do members of a built-in type always need to be initialised manually, and
c) are there any circumstances under which an object's storage is zeroed-out before the constructor is called?

Also, in researching this, I have seen the terms 'default-initialised' and 'zero-initialised' used - is there a difference between saying:

T a;

and

T a();

? I thought that the first form was just used to prevent ambiguity when the second may be taken by the compiler as a function declaration.

Thank you very much for your time,

stellarpower

like image 205
stellarpower Avatar asked Dec 08 '22 01:12

stellarpower


2 Answers

The term you are looking for is default initialized. Any instance data member will be default initialized if it is not explicitly initialized in the body of the constructor. What this means depends on whether the data member is a primitive data type or not and where the object instantiation takes place. In case of data members of non-primitive data types, the default constructor will be used (or the compiler will complain if there is no default constructor). In case of data members of primitive data types this means that they will not be initialized if the instantiation takes place on the stack or on the heap. If it is a global or a static variable however, the data members will be set to 0.

By the way, when you write

T a;

then you define a variable a of type T. When you write

T a();

then you declare a function a() which returns T by value.

like image 20
shargors Avatar answered Dec 26 '22 11:12

shargors


First let's go over some examples and the correct terminology.

T a1;            // default initialization
T a2{};          // value initialization
T();             // also value initialization
new T;           // default initialization
new T();         // value initialization
new T{};         // also value initialization
class C1 {
    C1() {}
    T x;
};               // no initializer for C1::x; default-initialized
class C2 {
    T x;
};               // implicit default constructor default-initializes C2::x
class C3 {
    C3() : x() {}
    T x;
};               // C3::x will be value-initialized.
class C4 {
    C4() : x{} {}
    T x;
};               // C4::x will also be value-initialized.
// DANGER
T a();           // declares a function; not value initialization (quirk of C++)

Generally, the rule is that when there is no initializer, it is default initialization, and when the initializer is () or {}, it is value initialization. Note that there is an exception for statics and thread-locals, which I'll discuss later.

For an integer or floating-point type, value initialization sets it to 0. For a pointer type, value initialization sets it to null. Default initialization does nothing for scalar types. Therefore, if an object of scalar type only receives default initialization, then it has indeterminate value.

a) Does initialisation of members of a built-in type have anything to do with wheher a user-defined constructor is defined or not,

The default constructor for a class default-initializes members. A member is also default-initialized when no mem-initializer is explicitly provided for it. The examples C1 and C2 illustrate this. However, note that when a class type is value-initialized, and the class's default constructor is either implicitly defined or explicitly defaulted, the class's members will be zeroed out. This zeroing out occurs only in this case, and doesn't occur for a user-provided default constructor. So the answer to your question is "yes" in this sense.

C1 y1;   // y1 is default-initialized; y1.x is indeterminate
C1 y2{}; // y2 is value-initialized;   y2.x is indeterminate
C2 y3;   // y3 is default-initialized; y3.x is indeterminate
C2 y4{}; // y4 is value-initialized;   y4.x is set to 0
C3 y5;   // y5 is default-initialized; y5.x is set to 0
C3 y6{}; // y6 is value-initialized;   y6.x is set to 0

b) do members of a built-in type always need to be initialised manually, and c) are there any circumstances under which an object's storage is zeroed-out before the constructor is called?

I assume you mean "class members with built-in type". I covered a case above in which they are automatically initialized to 0: where the class object is value-initialized and its constructor is not user-provided (or deleted). Another case is when the class object has static or thread-local storage duration. In this case, the members will also be zeroed out at the very beginning, so there is no chance of them ending up with indeterminate value.

like image 120
Brian Bi Avatar answered Dec 26 '22 12:12

Brian Bi