I'm partial to using member initialization lists with my constructors... but I've long since forgotten the reasons behind this...
Do you use member initialization lists in your constructors? If so, why? If not, why not?
For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:
B()
: a(3)
{
}
This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.
Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Apart from the performance reasons mentioned above, if your class stores references to objects passed as constructor parameters or your class has const variables then you don't have any choice except using initializer lists.
Initialization of base class
One important reason for using constructor initializer list which is not mentioned in answers here is initialization of base class.
As per the order of construction, base class should be constructed before child class. Without constructor initializer list, this is possible if your base class has default constructor which will be called just before entering the constructor of child class.
But, if your base class has only parameterized constructor, then you must use constructor initializer list to ensure that your base class is initialized before child class.
Initialization of Subobjects which only have parameterized constructors
Efficiency
Using constructor initializer list, you initialize your data members to exact state which you need in your code rather than first initializing them to their default state & then changing their state to the one you need in your code.
Initializing non-static const data members
If non-static const data members in your class have default constructors & you don't use constructor initializer list, you won't be able to initialize them to intended state as they will be initialized to their default state.
Initialization of reference data members
Reference data members must be intialized when compiler enters constructor as references can't be just declared & initialized later. This is possible only with constructor initializer list.
Next to the performance issues, there is another one very important which I'd call code maintainability and extendibility.
If a T is POD and you start preferring initialization list, then if one time T will change to a non-POD type, you won't need to change anything around initialization to avoid unnecessary constructor calls because it is already optimised.
If type T does have default constructor and one or more user-defined constructors and one time you decide to remove or hide the default one, then if initialization list was used, you don't need to update code of your user-defined constructors because they are already correctly implemented.
Same with const members or reference members, let's say initially T is defined as follows:
struct T
{
T() { a = 5; }
private:
int a;
};
Next, you decide to qualify a as const, if you would use initialization list from the beginning, then this was a single line change, but having the T defined as above, it also requires to dig the constructor definition to remove assignment:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
It's not a secret that maintenance is far easier and less error-prone if code was written not by a "code monkey" but by an engineer who makes decisions based on deeper consideration about what he is doing.
Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives.
If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows the following steps to create an object of type MyClass:
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside the body of MyClass() constructor to assign.
variable = a;
And then finally the destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with an Initializer List:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, the following steps are followed by the compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in the initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Need of Initialization list:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
in the above program, When the class’s constructor is executed, Sam_x and Sam_y are created. Then in constructor body, those member data variables are defined.
Use cases:
Const and Reference variables in a Class
In C, variables must be defined during creation. the same way in C++, we must initialize the Const and Reference variable during object creation by using Initialization list. if we do initialization after object creation (Inside constructor body), we will get compile time error.
Member objects of Sample1 (base) class which do not have default constructor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
While creating object for derived class which will internally calls derived class constructor and calls base class constructor (default). if base class does not have default constructor, user will get compile time error. To avoid, we must have either
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Class constructor’s parameter name and Data member of a Class are same:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
As we all know, local variable having highest priority then global variable if both variables are having same name. In this case, the program consider "i" value {both left and right side variable. i.e: i = i} as local variable in Sample3() constructor and Class member variable(i) got override. To avoid, we must use either
1. Initialization list
2. this operator.
Just to add some additional info to demonstrate how much difference the member initialization list can mak. In the leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/, where you need to construct and initialize to zero a vector with certain size. Here is two different implementation and speed comparison.
Without member initialization list, to get AC it cost me about 212 ms.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
Now using member initialization list, the time to get AC is about 108 ms. With this simple example, it is quite obvious that, member initialization list is way more efficient. All the measurement is from the running time from LC.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
As explained in the C++ Core Guidelines C.49: Prefer initialization to assignment in constructors
it prevents unnecessary calls to default constructors.
Related
Coming from JavaScript and Python, I'm trying to understand the nuances and purpose around C++ class constructors.
In the example below, why is it allowed to initialize attributes without a constructor?
class MyClass {
public:
int a = 1;
int b = 2;
};
Does the default constructor include the above definitions/initializations? What is the difference to the following two examples?:
1.
class MyClass {
public:
int a;
int b;
MyClass(){
a = 1;
b = 2;
}
};
JavaScript/Python style (Is this even possible?)
class MyClass {
public:
MyClass(){
// Some kind of variable declaration and definition like:
// this.a = 1;
// this.b = 2;
}
};
To me having the option of initialization without a constructor sounds like an overkill and is confusing. In both Python and JavaScript one usually declares and initializes all variables from the constructor, and only from there only.
What is the best practice here?
In the example below, why is it allowed to initialize attributes without a constructor?
Because C++11 specifically added that feature. See Member initialization.
Does the default constructor include the above definitions/initializations?
Yes. This code:
class MyClass {
public:
int a = 1;
int b = 2;
};
Is roughly (not exactly) equivalent to this code:
class MyClass {
public:
int a;
int b;
MyClass() : a(1), b(2) {}
};
It is actually possible to use both forms of initialization at the same time, eg:
class MyClass {
public:
int a = 1;
int b = 2;
MyClass() = default;
MyClass(int a) : a(a) {}
};
Per Member initialization:
Non-static data members may be initialized in one of two ways:
In the member initializer list of the constructor.
Through a default member initializer, which is a brace or equals initializer included in the member declaration and is used if the member is omitted from the member initializer list of a constructor.
If a member has a default member initializer and also appears in the member initialization list in a constructor, the default member initializer is ignored for that constructor.
The a member is not specified in the default constructor's member initialization list, so it will be initialized with its default value of 1 when a MyClass object is default constructed.
The a member is explicitly initialized in the converting constructor's member initialization list, so its default value of 1 will be ignored and it will instead be initialized with the caller-provided value when a MyClass object is constructed with an input value.
The b member is not specified in either constructor's member initialization list, so it will always be initialized with its default value of 2.
What is the difference to the following two examples?:
The first example is what you would have to do prior to C++11 (if you are not using the constructor's member initialization list, as shown above).
The second example is not legal in C++. You can't declare members dynamically, and certainly not from inside a constructor. They have to be declared statically in the class declaration itself.
I'm partial to using member initialization lists with my constructors... but I've long since forgotten the reasons behind this...
Do you use member initialization lists in your constructors? If so, why? If not, why not?
For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:
B()
: a(3)
{
}
This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.
Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Apart from the performance reasons mentioned above, if your class stores references to objects passed as constructor parameters or your class has const variables then you don't have any choice except using initializer lists.
Initialization of base class
One important reason for using constructor initializer list which is not mentioned in answers here is initialization of base class.
As per the order of construction, base class should be constructed before child class. Without constructor initializer list, this is possible if your base class has default constructor which will be called just before entering the constructor of child class.
But, if your base class has only parameterized constructor, then you must use constructor initializer list to ensure that your base class is initialized before child class.
Initialization of Subobjects which only have parameterized constructors
Efficiency
Using constructor initializer list, you initialize your data members to exact state which you need in your code rather than first initializing them to their default state & then changing their state to the one you need in your code.
Initializing non-static const data members
If non-static const data members in your class have default constructors & you don't use constructor initializer list, you won't be able to initialize them to intended state as they will be initialized to their default state.
Initialization of reference data members
Reference data members must be intialized when compiler enters constructor as references can't be just declared & initialized later. This is possible only with constructor initializer list.
Next to the performance issues, there is another one very important which I'd call code maintainability and extendibility.
If a T is POD and you start preferring initialization list, then if one time T will change to a non-POD type, you won't need to change anything around initialization to avoid unnecessary constructor calls because it is already optimised.
If type T does have default constructor and one or more user-defined constructors and one time you decide to remove or hide the default one, then if initialization list was used, you don't need to update code of your user-defined constructors because they are already correctly implemented.
Same with const members or reference members, let's say initially T is defined as follows:
struct T
{
T() { a = 5; }
private:
int a;
};
Next, you decide to qualify a as const, if you would use initialization list from the beginning, then this was a single line change, but having the T defined as above, it also requires to dig the constructor definition to remove assignment:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
It's not a secret that maintenance is far easier and less error-prone if code was written not by a "code monkey" but by an engineer who makes decisions based on deeper consideration about what he is doing.
Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives.
If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows the following steps to create an object of type MyClass:
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside the body of MyClass() constructor to assign.
variable = a;
And then finally the destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with an Initializer List:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, the following steps are followed by the compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in the initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Need of Initialization list:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
in the above program, When the class’s constructor is executed, Sam_x and Sam_y are created. Then in constructor body, those member data variables are defined.
Use cases:
Const and Reference variables in a Class
In C, variables must be defined during creation. the same way in C++, we must initialize the Const and Reference variable during object creation by using Initialization list. if we do initialization after object creation (Inside constructor body), we will get compile time error.
Member objects of Sample1 (base) class which do not have default constructor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
While creating object for derived class which will internally calls derived class constructor and calls base class constructor (default). if base class does not have default constructor, user will get compile time error. To avoid, we must have either
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Class constructor’s parameter name and Data member of a Class are same:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
As we all know, local variable having highest priority then global variable if both variables are having same name. In this case, the program consider "i" value {both left and right side variable. i.e: i = i} as local variable in Sample3() constructor and Class member variable(i) got override. To avoid, we must use either
1. Initialization list
2. this operator.
Just to add some additional info to demonstrate how much difference the member initialization list can mak. In the leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/, where you need to construct and initialize to zero a vector with certain size. Here is two different implementation and speed comparison.
Without member initialization list, to get AC it cost me about 212 ms.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
Now using member initialization list, the time to get AC is about 108 ms. With this simple example, it is quite obvious that, member initialization list is way more efficient. All the measurement is from the running time from LC.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
As explained in the C++ Core Guidelines C.49: Prefer initialization to assignment in constructors
it prevents unnecessary calls to default constructors.
I'm partial to using member initialization lists with my constructors... but I've long since forgotten the reasons behind this...
Do you use member initialization lists in your constructors? If so, why? If not, why not?
For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:
B()
: a(3)
{
}
This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.
Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Apart from the performance reasons mentioned above, if your class stores references to objects passed as constructor parameters or your class has const variables then you don't have any choice except using initializer lists.
Initialization of base class
One important reason for using constructor initializer list which is not mentioned in answers here is initialization of base class.
As per the order of construction, base class should be constructed before child class. Without constructor initializer list, this is possible if your base class has default constructor which will be called just before entering the constructor of child class.
But, if your base class has only parameterized constructor, then you must use constructor initializer list to ensure that your base class is initialized before child class.
Initialization of Subobjects which only have parameterized constructors
Efficiency
Using constructor initializer list, you initialize your data members to exact state which you need in your code rather than first initializing them to their default state & then changing their state to the one you need in your code.
Initializing non-static const data members
If non-static const data members in your class have default constructors & you don't use constructor initializer list, you won't be able to initialize them to intended state as they will be initialized to their default state.
Initialization of reference data members
Reference data members must be intialized when compiler enters constructor as references can't be just declared & initialized later. This is possible only with constructor initializer list.
Next to the performance issues, there is another one very important which I'd call code maintainability and extendibility.
If a T is POD and you start preferring initialization list, then if one time T will change to a non-POD type, you won't need to change anything around initialization to avoid unnecessary constructor calls because it is already optimised.
If type T does have default constructor and one or more user-defined constructors and one time you decide to remove or hide the default one, then if initialization list was used, you don't need to update code of your user-defined constructors because they are already correctly implemented.
Same with const members or reference members, let's say initially T is defined as follows:
struct T
{
T() { a = 5; }
private:
int a;
};
Next, you decide to qualify a as const, if you would use initialization list from the beginning, then this was a single line change, but having the T defined as above, it also requires to dig the constructor definition to remove assignment:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
It's not a secret that maintenance is far easier and less error-prone if code was written not by a "code monkey" but by an engineer who makes decisions based on deeper consideration about what he is doing.
Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives.
If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows the following steps to create an object of type MyClass:
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside the body of MyClass() constructor to assign.
variable = a;
And then finally the destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with an Initializer List:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, the following steps are followed by the compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in the initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Need of Initialization list:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
in the above program, When the class’s constructor is executed, Sam_x and Sam_y are created. Then in constructor body, those member data variables are defined.
Use cases:
Const and Reference variables in a Class
In C, variables must be defined during creation. the same way in C++, we must initialize the Const and Reference variable during object creation by using Initialization list. if we do initialization after object creation (Inside constructor body), we will get compile time error.
Member objects of Sample1 (base) class which do not have default constructor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
While creating object for derived class which will internally calls derived class constructor and calls base class constructor (default). if base class does not have default constructor, user will get compile time error. To avoid, we must have either
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Class constructor’s parameter name and Data member of a Class are same:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
As we all know, local variable having highest priority then global variable if both variables are having same name. In this case, the program consider "i" value {both left and right side variable. i.e: i = i} as local variable in Sample3() constructor and Class member variable(i) got override. To avoid, we must use either
1. Initialization list
2. this operator.
Just to add some additional info to demonstrate how much difference the member initialization list can mak. In the leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/, where you need to construct and initialize to zero a vector with certain size. Here is two different implementation and speed comparison.
Without member initialization list, to get AC it cost me about 212 ms.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
Now using member initialization list, the time to get AC is about 108 ms. With this simple example, it is quite obvious that, member initialization list is way more efficient. All the measurement is from the running time from LC.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
As explained in the C++ Core Guidelines C.49: Prefer initialization to assignment in constructors
it prevents unnecessary calls to default constructors.
I'm partial to using member initialization lists with my constructors... but I've long since forgotten the reasons behind this...
Do you use member initialization lists in your constructors? If so, why? If not, why not?
For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:
B()
: a(3)
{
}
This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.
Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Apart from the performance reasons mentioned above, if your class stores references to objects passed as constructor parameters or your class has const variables then you don't have any choice except using initializer lists.
Initialization of base class
One important reason for using constructor initializer list which is not mentioned in answers here is initialization of base class.
As per the order of construction, base class should be constructed before child class. Without constructor initializer list, this is possible if your base class has default constructor which will be called just before entering the constructor of child class.
But, if your base class has only parameterized constructor, then you must use constructor initializer list to ensure that your base class is initialized before child class.
Initialization of Subobjects which only have parameterized constructors
Efficiency
Using constructor initializer list, you initialize your data members to exact state which you need in your code rather than first initializing them to their default state & then changing their state to the one you need in your code.
Initializing non-static const data members
If non-static const data members in your class have default constructors & you don't use constructor initializer list, you won't be able to initialize them to intended state as they will be initialized to their default state.
Initialization of reference data members
Reference data members must be intialized when compiler enters constructor as references can't be just declared & initialized later. This is possible only with constructor initializer list.
Next to the performance issues, there is another one very important which I'd call code maintainability and extendibility.
If a T is POD and you start preferring initialization list, then if one time T will change to a non-POD type, you won't need to change anything around initialization to avoid unnecessary constructor calls because it is already optimised.
If type T does have default constructor and one or more user-defined constructors and one time you decide to remove or hide the default one, then if initialization list was used, you don't need to update code of your user-defined constructors because they are already correctly implemented.
Same with const members or reference members, let's say initially T is defined as follows:
struct T
{
T() { a = 5; }
private:
int a;
};
Next, you decide to qualify a as const, if you would use initialization list from the beginning, then this was a single line change, but having the T defined as above, it also requires to dig the constructor definition to remove assignment:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
It's not a secret that maintenance is far easier and less error-prone if code was written not by a "code monkey" but by an engineer who makes decisions based on deeper consideration about what he is doing.
Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives.
If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows the following steps to create an object of type MyClass:
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside the body of MyClass() constructor to assign.
variable = a;
And then finally the destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with an Initializer List:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, the following steps are followed by the compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in the initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Need of Initialization list:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
in the above program, When the class’s constructor is executed, Sam_x and Sam_y are created. Then in constructor body, those member data variables are defined.
Use cases:
Const and Reference variables in a Class
In C, variables must be defined during creation. the same way in C++, we must initialize the Const and Reference variable during object creation by using Initialization list. if we do initialization after object creation (Inside constructor body), we will get compile time error.
Member objects of Sample1 (base) class which do not have default constructor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
While creating object for derived class which will internally calls derived class constructor and calls base class constructor (default). if base class does not have default constructor, user will get compile time error. To avoid, we must have either
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Class constructor’s parameter name and Data member of a Class are same:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
As we all know, local variable having highest priority then global variable if both variables are having same name. In this case, the program consider "i" value {both left and right side variable. i.e: i = i} as local variable in Sample3() constructor and Class member variable(i) got override. To avoid, we must use either
1. Initialization list
2. this operator.
Just to add some additional info to demonstrate how much difference the member initialization list can mak. In the leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/, where you need to construct and initialize to zero a vector with certain size. Here is two different implementation and speed comparison.
Without member initialization list, to get AC it cost me about 212 ms.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
Now using member initialization list, the time to get AC is about 108 ms. With this simple example, it is quite obvious that, member initialization list is way more efficient. All the measurement is from the running time from LC.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
As explained in the C++ Core Guidelines C.49: Prefer initialization to assignment in constructors
it prevents unnecessary calls to default constructors.
I'm partial to using member initialization lists with my constructors... but I've long since forgotten the reasons behind this...
Do you use member initialization lists in your constructors? If so, why? If not, why not?
For POD class members, it makes no difference, it's just a matter of style. For class members which are classes, then it avoids an unnecessary call to a default constructor. Consider:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
In this case, the constructor for B will call the default constructor for A, and then initialize a.x to 3. A better way would be for B's constructor to directly call A's constructor in the initializer list:
B()
: a(3)
{
}
This would only call A's A(int) constructor and not its default constructor. In this example, the difference is negligible, but imagine if you will that A's default constructor did more, such as allocating memory or opening files. You wouldn't want to do that unnecessarily.
Furthermore, if a class doesn't have a default constructor, or you have a const member variable, you must use an initializer list:
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
Apart from the performance reasons mentioned above, if your class stores references to objects passed as constructor parameters or your class has const variables then you don't have any choice except using initializer lists.
Initialization of base class
One important reason for using constructor initializer list which is not mentioned in answers here is initialization of base class.
As per the order of construction, base class should be constructed before child class. Without constructor initializer list, this is possible if your base class has default constructor which will be called just before entering the constructor of child class.
But, if your base class has only parameterized constructor, then you must use constructor initializer list to ensure that your base class is initialized before child class.
Initialization of Subobjects which only have parameterized constructors
Efficiency
Using constructor initializer list, you initialize your data members to exact state which you need in your code rather than first initializing them to their default state & then changing their state to the one you need in your code.
Initializing non-static const data members
If non-static const data members in your class have default constructors & you don't use constructor initializer list, you won't be able to initialize them to intended state as they will be initialized to their default state.
Initialization of reference data members
Reference data members must be intialized when compiler enters constructor as references can't be just declared & initialized later. This is possible only with constructor initializer list.
Next to the performance issues, there is another one very important which I'd call code maintainability and extendibility.
If a T is POD and you start preferring initialization list, then if one time T will change to a non-POD type, you won't need to change anything around initialization to avoid unnecessary constructor calls because it is already optimised.
If type T does have default constructor and one or more user-defined constructors and one time you decide to remove or hide the default one, then if initialization list was used, you don't need to update code of your user-defined constructors because they are already correctly implemented.
Same with const members or reference members, let's say initially T is defined as follows:
struct T
{
T() { a = 5; }
private:
int a;
};
Next, you decide to qualify a as const, if you would use initialization list from the beginning, then this was a single line change, but having the T defined as above, it also requires to dig the constructor definition to remove assignment:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
It's not a secret that maintenance is far easier and less error-prone if code was written not by a "code monkey" but by an engineer who makes decisions based on deeper consideration about what he is doing.
Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives.
If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows the following steps to create an object of type MyClass:
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside the body of MyClass() constructor to assign.
variable = a;
And then finally the destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with an Initializer List:
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, the following steps are followed by the compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in the initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
Syntax:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
Need of Initialization list:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
in the above program, When the class’s constructor is executed, Sam_x and Sam_y are created. Then in constructor body, those member data variables are defined.
Use cases:
Const and Reference variables in a Class
In C, variables must be defined during creation. the same way in C++, we must initialize the Const and Reference variable during object creation by using Initialization list. if we do initialization after object creation (Inside constructor body), we will get compile time error.
Member objects of Sample1 (base) class which do not have default constructor
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
While creating object for derived class which will internally calls derived class constructor and calls base class constructor (default). if base class does not have default constructor, user will get compile time error. To avoid, we must have either
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
Class constructor’s parameter name and Data member of a Class are same:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
As we all know, local variable having highest priority then global variable if both variables are having same name. In this case, the program consider "i" value {both left and right side variable. i.e: i = i} as local variable in Sample3() constructor and Class member variable(i) got override. To avoid, we must use either
1. Initialization list
2. this operator.
Just to add some additional info to demonstrate how much difference the member initialization list can mak. In the leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/, where you need to construct and initialize to zero a vector with certain size. Here is two different implementation and speed comparison.
Without member initialization list, to get AC it cost me about 212 ms.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
Now using member initialization list, the time to get AC is about 108 ms. With this simple example, it is quite obvious that, member initialization list is way more efficient. All the measurement is from the running time from LC.
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
As explained in the C++ Core Guidelines C.49: Prefer initialization to assignment in constructors
it prevents unnecessary calls to default constructors.