Constructor Initialization VS Assignment

Constructor initialization Vs assignment

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.

Initializer list vs Constructor assignment vs variable defining

This excerpt has been taken from "Inside the C++ Object Model" by Stanley B. Lippman.

You must use the member initialization list in the following cases in
order for your program to compile:

1. When initializing a reference member

2. When initializing a const member

3. When invoking a base or member class constructor with a set of arguments

4. A few efficiency cases. (Here the program is correct w/o member initialization list)

For points 1-3, member initialization list is a must.

For point 4, it is not compulsory.

For example(point 4), given :

class Word {
String _name;
int _cnt;
public:
// not wrong, just naive ...
Word() {
_name = 0;
_cnt = 0;
}
};

This implementation of the Word constructor initializes _name once, then overrides the initialization with an assignment, resulting in the creation and the destruction of a temporary String object.

A significantly more efficient implementation would have been coded:

// preferred implementation
Word::Word : _name( 0 )
{
_cnt = 0;
}

Due to this optimisation, a lot of people prefer member initialization list, as a default approach to write constructors.

// some insist on this coding style
Word::Word()
: _cnt( 0 ), _name( 0 )
{}

A reasonable question to ask at this point is, what actually happens to the member initialization list?

The compiler iterates over the initialization list, inserting the initializations in the proper order within the constructor prior to any explicit user code.

For example, the previous Word constructor is expanded as follows:

// Pseudo C++ Code
Word::Word( /* this pointer goes here */ )
{
_name.String::String( 0 );
_cnt = 0;
}

Note : The order in which the list entries are set down is determined
by the declaration order of the members within the class declaration,
not the order within the initialization list. In this case, _name is
declared before _cnt in Word and so is placed first.

So coming back to your question :

class B is fine(since you are using primitive datatypes).

class A will generate the same code as class B

As for class C, the default constructor is first called, and then initialization of width and height would happen. This method should be preferred when there are going to be more than 1 constructor, and for each constructor width and height need to be defaulted to your desired values.

However, since the advent of C++11, and use of {} as uniform initialization, a more recommended approach for writing class C would be :

class C
{
public:
int width {500};
int height {300};
};

C++: initialize vs assignment?

The curly braces is part of uniform initialization which was added with the C++11 standard.

Using

int value {1};

is equivalent to

int value = 1;

There's some differences between using curly braces and "assignment" syntax for initialization of variables, but in this simple case they're equal.

Initialisation and assignment

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.,

Constructor initializer list vs initializing in the header file

This:

MyClass::MyClass()
{
variable1 = 10;
boolean2 = false;
};

is not initialization! The members will be initialized before the body of the constructor runs and then you are assigning values. What you mean is probably the difference between

Initializer list

MyClass::MyClass() : variable1(10), boolean2(false) {}

and in class initialization (available since C++11 I believe) in the header:

struct MyClass {
int variable1 = 10;
boolean2 = false;
};

In both the last cases, the values are used to initialize the members, so there is no difference in speed. However, in the first case you are doing more than you actually want to (initialization + assignment) and you should avoid it if possible.

The subtle difference between in-class initialization and initializer list (see eg here) is that

variable1 = 10; 

may involve a copy. This can be circumvented by using direct-list-initialization:

 struct MyClass {
int variable1{10};
bool boolean2{false};
};

However, for an int and a bool this wont make any difference whatsoever.

Initializer list vs Constructor assignment vs variable defining

This excerpt has been taken from "Inside the C++ Object Model" by Stanley B. Lippman.

You must use the member initialization list in the following cases in
order for your program to compile:

1. When initializing a reference member

2. When initializing a const member

3. When invoking a base or member class constructor with a set of arguments

4. A few efficiency cases. (Here the program is correct w/o member initialization list)

For points 1-3, member initialization list is a must.

For point 4, it is not compulsory.

For example(point 4), given :

class Word {
String _name;
int _cnt;
public:
// not wrong, just naive ...
Word() {
_name = 0;
_cnt = 0;
}
};

This implementation of the Word constructor initializes _name once, then overrides the initialization with an assignment, resulting in the creation and the destruction of a temporary String object.

A significantly more efficient implementation would have been coded:

// preferred implementation
Word::Word : _name( 0 )
{
_cnt = 0;
}

Due to this optimisation, a lot of people prefer member initialization list, as a default approach to write constructors.

// some insist on this coding style
Word::Word()
: _cnt( 0 ), _name( 0 )
{}

A reasonable question to ask at this point is, what actually happens to the member initialization list?

The compiler iterates over the initialization list, inserting the initializations in the proper order within the constructor prior to any explicit user code.

For example, the previous Word constructor is expanded as follows:

// Pseudo C++ Code
Word::Word( /* this pointer goes here */ )
{
_name.String::String( 0 );
_cnt = 0;
}

Note : The order in which the list entries are set down is determined
by the declaration order of the members within the class declaration,
not the order within the initialization list. In this case, _name is
declared before _cnt in Word and so is placed first.

So coming back to your question :

class B is fine(since you are using primitive datatypes).

class A will generate the same code as class B

As for class C, the default constructor is first called, and then initialization of width and height would happen. This method should be preferred when there are going to be more than 1 constructor, and for each constructor width and height need to be defaulted to your desired values.

However, since the advent of C++11, and use of {} as uniform initialization, a more recommended approach for writing class C would be :

class C
{
public:
int width {500};
int height {300};
};

Order of In Class Initialization versus Constructor Initialization List

This is guaranteed by the standard that non-static data members will be initialized in the order of their declarations in the class definition. How they're initialized (via default member initializer or member initializer list) and the order of these initializers don't matter.

[class.base.init]#13.3

(13.3) - Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

That means, the initialization order will always be ptr -> m1 -> m2.

C++ Constructors vs Initialization Lists speed comparison

The difference is for types with no trivial default constructor, which is called for you by compiler in your class B. Your class B is equivalent to:

 class B {
private:
SleepyInt a, b;

public:
// takes at least 20s
B(int a_var, int b_var) : a(), b()
// ^^^^^^^^^^
{
a = a_var;
b = b_var;
}
};

If you do not place member variable or base class constructor in initialization list - ithe default constructor is called for them. int is basic type - its default constructor costs nothing - so no difference in your example, but for more complex types constructor+assignment might cost more than just constructing.

Some funny example, just to illustrate the difference:

class SleepyInt {
public:
SleepyInt () {
std::this_thread::sleep_for(std::chrono::milliseconds( 10000 ));
}
SleepyInt (int i) {}
SleepyInt & operator = (int i) { return *this; }
};

class A {
private:
SleepyInt a, b;

public:
A(int a_var, int b_var):a(a_var), b(b_var) {};
};

class B {
private:
SleepyInt a, b;

public:
// takes at least 20s
B(int a_var, int b_var) {
a = a_var;
b = b_var;
}
};


Related Topics



Leave a reply



Submit