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
inWord
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
inWord
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
How to Track Memory Allocations in C++ (Especially New/Delete)
Calling a Function Through Its Address in Memory in C/C++
How to Effectively Kill a Process in C++ (Win32)
C++ View Types: Pass by Const& or by Value
Qt - Remove All Widgets from Layout
C++11 Variable Number of Arguments, Same Specific Type
Performance Wise, How Fast Are Bitwise Operators VS. Normal Modulus
Show Two Digits After Decimal Point in C++
What Is a "Regular Type" in the Context of Move Semantics
_Attribute_((Weak)) and Static Libraries
Cc1Plus: Error: Unrecognized Command Line Option "-Std=C++11" with G++
Using Std::Move() When Returning a Value from a Function to Avoid to Copy
Std::Mutex Performance Compared to Win32 Critical_Section
Template Function Specialization for Integer Types
Are Global Variables in C++ Stored on the Stack, Heap or Neither of Them