How does a constructor create and initialize member variables? - c++

Consider the following class with member initializer list:
class A {
public:
A() : a {b} {
// do something
}
private:
int a {1};
int b {2};
};
The compiler issues a warning that b is used uninitialized in the member initalizer list. This would mean, the member b has been already created but not initialized yet?
Thus, can we assume the following order of execution?
call constructor A()
int a; (create memory for a)
int b; (create memory for b)
a = b; (compiler warning)
b = 2; (assign default 2 to b)
execute constructor's block
This would mean, we actually do not initialize but assign values in step 4 and 5?
EDIT:
If so, what is the advantage of an initializer list, when assignments can also be done in the block after the members have been created prior entering the block?

The sequence you describe is not completely correct. The sequence goes basically as follows:
The memory for the object is allocated; (e.g. using operator new) Note that the memory is not allocated separately. The memory for the object is continuous, possibly with padding in between a and b.
Initializations of members are done where initializers are provided in the initializer list of the constructor or directly at the member declaration. in this case a is declared first then b which is why b has not been initialized at the time you try to read it to initialize a.
The constructor body is executed.
Note that the fields are initialized, not assigned which in case of ints doesn't make a difference, but if the member types would provide assignment operators and constructors there would be a difference between the 2; if you use the initializer list or initialize the member variable when declaring it the constructor is always used.

Related

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
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.
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.
One way to default initialize all member variables without calling a constructor would be if you have a POD type. For e.g. this is a POD
class Foo {
int num1;
double num2;
bool b;
int *pnum;
};
and if you do
Foo foo = {};
everything will be zero-initialized (b will be false, pnum NULL etc) without calling the (default) constructor.
So
a) a POD type must not have a user defined constructor so in that case yes
b) if you have a POD you don't have to initialize them manually
c) if you have a POD type you can zero-initialize without calling a constructor.
Another way to create a class instance and zero-initialize without calling a constructor would be to allocate the required memory with calloc and cast the pointer to the required type. You should avoid that unless absolutely necessary!

Constructor initialization Vs assignment

Let us consider the following classes
class test1
{
private:
int a;
int b;
public:
test1():a(0),b(0){}
};
class test2
{
private:
int a;
int b;
public:
test2()
{
a=0;
b=0;
}
};
Now, I know that test1() constructor is the right way to initialize the data members of a class, because in test2() we are performing assignment and not initialization. My questions are:
What might go wrong if we perform assignment instead of initialization?
Doesn't the compiler internally perform assignment in case of test1() constructor? If not, then how are these initialized?
What might go wrong if we perform assignment instead of initialization?
Some class types (and also references and const objects) can't be assigned; some can't be default-initialised; some might be more expensive to default-initialise and reassign than to initialise directly.
Doesn't the compiler internally performs assignment in case of test1() constructor? If no then how are these initialized?
In the case of primitive types like int, there is little or no practical difference between the two. Default-initialisation does nothing, and direct-initialisation and assignment both do essentially the same thing.
In the case of class types, default-initialisation, assignment and direct-initialisation each call different user-defined functions, and some operations may not exist at all; so in general the two examples could have very different behaviour.
For your example there is no real different because you are initializing plain integers.
But assume these integers are objects with constructors, then the compiler would generate the following calls:
// test1
a::copy_constructor(0);
b::copy_constructor(0);
// test2
a::default_constructor();
b::default_constructor();
a::operator = (0);
b::operator = (0);
So depending on your objects test2 could have a huge performance impact. Also by initializing your objects in the initializing lists guaranties that your variables have the data when you enter the constructor. One 'drawback' of the initializer list is that the it is executed in the order that the variables are declared and not in the order of the initializer list, so it could be that you don't want to use the initializer list.
A third variant utilizing direct-list-initialization. Advantages are
variables don't have to be default-initialized in the constructor
the constructor and not the copy/move assignment operator is used to construct the members (as the other answers said, it doesn't matter for the primitive type of this example)
So this is less error-prone than both variants in the question:
#include <iostream>
class Test3
{
public: // Made public so we can easily output the vars. No struct is used to be consistent with question.
int a { 4 }; // No need for separate initialization in constructor.
int b { 2 }; // No need for separate initialization in constructor.
};
int main()
{
const auto t = std::move(Test3()); // Implicitly-declared default constructor + implicitly-declared move assignment operator
std::cout << t.a << t.b;
}
Output is 42.
Constructor-initializers allow initialization of data members at the time of their
creation.
Some programmers prefer to assign initial values in the body of the constructor. However, several data types must be initialized in a constructor-initializer. The following lines summarizes them:
const data members
You cannot legally assign a value to a const variable
after it is created. Any value must be supplied at the
time of creation.
Reference data members
References cannot exist without referring to
something.
Object data members for which there is no default constructor
C++ attempts to initialize member objects using a
default constructor. If no default constructor exists, it
cannot initialize the object.

Why constant data member of a class need to be initialized at the constructor?

I want to know why constant data member of a class need to be initialized at the constructor and why not somewhere else? What is the impact of doing so and not doing so?
I also see that only static constant integral data can be initialized inside the class other than that non of the data members can be initialized inside the class.
for eg:- Suppose below is my class declaration
class A{
int a; // This we can initialize at the constructor or we can set this member by calling "vSet" member function
const int b;
static const int c = 10; //This works fine
public:
A();
~A();
void vSet(int a);
int iAdd();
void vDisplay();
};
And the constructor is defined as mentioned below:-
Edited Section: As previous constructor definition example was wrong
A::A():a(1),b(9){}
Please correct me if I am wrong.
Thanks in advance.
A::A(){
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
Is not initialization but it is Assignment.
a and b are already constructed and you assign them values in this case. The const qualifier demands that the variable not be changed after its initialization, allowing this assignment would break that contract.
This is Initialization using Member Initialization list.
A::A():a(1),b(9)
{}
You might want to have a look at this answer of mine to know the difference:
What is the difference between Initializing and Assignment inside constructor?
As for another question, regarding only static constant integral data can be initialized inside the class, please read this answer of mine which explains in greater detail:
Why I can't initialize non-const static member or static array in class?
What you're doing is not initialization. It is assignment, so b=9 will NOT even compile, because b is a const, so cannot be assigned any value to it. It should be initialized, and to do that, use member-initialization list as:
A::A() : a(1), b(9)
{ // ^^^^^^^^^^^^ this is called member-initialization list
}
In C++11, you can use in-place initialization as:
class A{
int a = 1; //C++11 only
const int b = 9; //C++11 only
static const int c = 10; //This works fine (both in C++03 and C++11)
//...
};
Because it is constant, it's value cannot be changed. Initializing anywhere else other than the constructor would mean a default initialization, followed by an assignment, which is not permitted for a constant. It would be the equivalent of doing this:
const int i; // OK
i = 42; // Error!
Note that in C++11 it is perfectly OK to do this:
struct Foo {
const int i=42;
const double x = 3.1416;
};
But this follows the same rules, i.e there is no assignment.
A const data is a data that can never be changed. It is initialized once, and then keeps the same value forever.
Because of that, you can't just assign a value to it anywhere.
The constructor, however, is where initialization goes. So here, there is an exception, and you are able to assign a value to your const data. You can do this the classical way, or as many said, as initialization list.
Now, why you can't do this in the class definition (unlike, say, Java) when the variable is not static is another problem, that I know no answer to.
When the body of your constructor is entered, all members and sub-objects are already initialized. The only thing the constructor body can do is to change them – and that is, obviously, not allowed for const members.
You can, however, use an initializer list.
You can't initialize const members outside of a constructor because, well, they're const. By definition, you can't modify them after they've been initialized, and after the object has been constructed, anything that tries to set the value is a modification.
const values are meant to be rvalues, so they cannot appear on the right part of an expression due its constness.
so, when you use this expression on the constructor's body
A::A()
{
a = 1;
b = 9; // Why we need to initialize this only at the constructor.
}
You're using the const value as a lvalue, just as Als mentioned before. The fact is that you're trying to assing a new value to a variable that isn't allowed to change it's value afther it's lifetime had begun.
The correct way to assign values to a constant data member is in the ctor initializer list, that is, BEFORE the lifetime of the member value begins (as mentioned by Nawaz):
A::A() :
a(1),
b(9)
{
}
Finally, on the C++11 standard you're allowed to initialize all data members where it was declared, just like the static const ones.

Initialisation and assignment

What EXACTLY is the difference between INITIALIZATION and ASSIGNMENT ?
PS : If possible please give examples in C and C++ , specifically .
Actually , I was confused by these statements ...
C++ provides another way of initializing member variables that allows us to initialize member variables when they are created rather than afterwards. This is done through use of an initialization list.
Using an initialization list is very similar to doing implicit assignments.
Oh my. Initialization and assignment. Well, that's confusion for sure!
To initialize is to make ready for use. And when we're talking about a variable, that means giving the variable a first, useful value. And one way to do that is by using an assignment.
So it's pretty subtle: assignment is one way to do initialization.
Assignment works well for initializing e.g. an int, but it doesn't work well for initializing e.g. a std::string. Why? Because the std::string object contains at least one pointer to dynamically allocated memory, and
if the object has not yet been initialized, that pointer needs to be set to point at a properly allocated buffer (block of memory to hold the string contents), but
if the object has already been initialized, then an assignment may have to deallocate the old buffer and allocate a new one.
So the std::string object's assignment operator evidently has to behave in two different ways, depending on whether the object has already been initialized or not!
Of course it doesn't behave in two different ways. Instead, for a std::string object the initialization is taken care of by a constructor. You can say that a constructor's job is to take the area of memory that will represent the object, and change the arbitrary bits there to something suitable for the object type, something that represents a valid object state.
That initialization from raw memory should ideally be done once for each object, before any other operations on the object.
And the C++ rules effectively guarantee that. At least as long as you don't use very low level facilities. One might call that the C++ construction guarantee.
So, this means that when you do
std::string s( "one" );
then you're doing simple construction from raw memory, but when you do
std::string s;
s = "two";
then you're first constructing s (with an object state representing an empty string), and then assigning to this already initialized s.
And that, finally, allows me to answer your question. From the point of view of language independent programming the first useful value is presumably the one that's assigned, and so in this view one thinks of the assignment as initialization. Yet, at the C++ technical level initialization has already been done, by a call of std::string's default constructor, so at this level one thinks of the declaration as initialization, and the assignment as just a later change of value.
So, especially the term "initialization" depends on the context!
Simply apply some common sense to sort out what Someone Else probably means.
Cheers & hth.,
In the simplest of terms:
int a = 0; // initialization of a to 0
a = 1; // assignment of a to 1
For built in types its relatively straight forward. For user defined types it can get more complex. Have a look at this article.
For instance:
class A
{
public:
A() : val_(0) // initializer list, initializes val_
{}
A(const int v) : val_(v) // initializes val_
{}
A(const A& rhs) : val_(rhs.val_) // still initialization of val_
{}
private:
int val_;
};
// all initialization:
A a;
A a2(4);
A a3(a2);
a = a3; // assignment
Initialization is creating an instance(of type) with certain value.
int i = 0;
Assignment is to give value to an already created instance(of type).
int i;
i = 0
To Answer your edited Question:
What is the difference between Initializing And Assignment inside constructor? &
What is the advantage?
There is a difference between Initializing a member using initializer list and assigning it an value inside the constructor body.
When you initialize fields via initializer list the constructors will be called once.
If you use the assignment then the fields will be first initialized with default constructors and then reassigned (via assignment operator) with actual values.
As you see there is an additional overhead of creation & assignment in the latter, which might be considerable for user defined classes.
For an integer data type or POD class members there is no practical overhead.
An Code Example:
class Myclass
{
public:
Myclass (unsigned int param) : param_ (param)
{
}
unsigned int param () const
{
return param_;
}
private:
unsigned int param_;
};
In the above example:
Myclass (unsigned int param) : param_ (param)
This construct is called a Member Initializer List in C++.
It initializes a member param_ to a value param.
When do you HAVE TO use member Initializer list?
You will have(rather forced) to use a Member Initializer list if:
Your class has a reference member
Your class has a const member or
Your class doesn't have a default constructor
Initialisation: giving an object an initial value:
int a(0);
int b = 2;
int c = a;
int d(c);
std::vector<int> e;
Assignment: assigning a new value to an object:
a = b;
b = 5;
c = a;
d = 2;
In C the general syntax for initialization is with {}:
struct toto { unsigned a; double c[2] };
struct toto T = { 3, { 4.5, 3.1 } };
struct toto S = { .c = { [1] = 7.0 }, .a = 32 };
The one for S is called "designated initializers" and is only available from C99 onward.
Fields that are omitted are automatically initialized with the
correct 0 for the corresponding type.
this syntax applies even to basic data types like double r = { 1.0
};
There is a catchall initializer that sets all fields to 0, namely { 0 }.
if the variable is of static linkage all expressions of the
initializer must be constant expressions
This {} syntax can not be used directly for assignment, but in C99 you can use compound literals instead like
S = (struct toto){ .c = { [1] = 5.0 } };
So by first creating a temporary object on the RHS and assigning this to your object.
One thing that nobody has yet mentioned is the difference between initialisation and assignment of class fields in the constructor.
Let us consider the class:
class Thing
{
int num;
char c;
public:
Thing();
};
Thing::Thing()
: num(5)
{
c = 'a';
}
What we have here is a constructor that initialises Thing::num to the value of 5, and assigns 'a' to Thing::c. In this case the difference is minor, but as was said before if you were to substitute int and char in this example for some arbitrary classes, we would be talking about the difference between calling a parameterised constructor versus a default constructor followed by operator= function.

class initialization list

Just a simple question about c++ coding style,
for example, all member variables of a class will be called with the default constructor in the initialization list if we don't do anything else. B default constructor will be called and value will be set to 0, int();
class A
{
A();
private:
B b;
int value;
}
However my question is, even do the default constructor will be called is it a good habit to always do it yourself or does it only add extra lines to the code
A::A() : b(), value() {}
You are touching on one of the sticky corners of C++.
The initialization of POD values in objects is sticky and depends on a few things.
Even I am not sure I can get all the rules correct but I believe #Steve Jessop once wrote an article about here on SO (though I can currently find it).
But some examples:
This class will always be initialized b == false and value = 0.
class A
{
A() : b(), value() {}
B b;
int value;
};
Without an explicit default constructor it is more complex:
Here the compiler will generate a default constructor for you. But how the compiler generated default constructor works depends on the situation. The compiler generated default constructor can do two different forms of initialization and which is used depends on context:
Zero Initialization (All POD members are zero'ed out)
Value Initialization (All POD members are left undefined)
Example:
class B
{
B b;
int value;
};
// Variables of static storage duration (notably globals)
// Will be zero initialized and thus b == false and value = 0
B global; // Initialized
int main()
{
// Object of automatic storage duration or dynamic storage duration
// These will depend on how they are declared.
// Value Initialization (POD re-mains undefined)
B bo1; // b/value undefined
B* bp1 = new B; // b.balue undefined
// Zero Initialization
B bo2 = B(); // b = false, value = 0
B* bp2 = new B(); // b = false, value = 0
// Note: The most obvious syntax for zero initializing a local object
// does not work as it is actually interpreted as a forward
// declaration of a function;
B bo3();
}
It's a good idea to leave the default constructor out. The compiler-generated constructors are much more reliable and maintainable than writing your own versions, and apart from anything else, it's a flat out waste of time to write code the compiler could write for you. If you don't need any construction logic, then don't write a constructor.
However, the int will not be initialized unless you do it, which is a sucky reason to have to write a constructor.
By default int variables are not initialized with a value - you have to do it yourself.
So when you don't set the member variable "value" to some value in the constructor it is left uninitialized.
The default constructor will only be called for class types with default constructors, not for primitives.