An initializer list is used to initialize the data members of a class. This list of members to be initialized is specified in the constructor as a comma-separated list, followed by a colon. Here is an example that demonstrates the use of an initializer list to initialize the variables x and y in the Point class.
#include<iostream>
using namespace std;
class Point {
private:
int x;
int y;
public:
Point(int i = 0, int j = 0):x(i), y(j) {}
/* The above use of the Initializer list is optional as the
constructor can also be written as:
Point(int i = 0, int j = 0) {
x = i;
y = j;
}
*/
int getX() const {return x;}
int getY() const {return y;}
};
int main() {
Point t1(10, 15);
cout<<"x = "<<t1.getX()<<", ";
cout<<"y = "<<t1.getY();
return 0;
}
/* OUTPUT:
x = 10, y = 15
*/
The code provided serves as an example of the syntax used for an initializer list. While the variables x and y can also be initialized within the constructor, there are specific scenarios where initializing data members inside the constructor is not effective. In these cases, an initializer list must be employed. Here are those situations:
1) For initialization of non-static const data members:
Const data members must be initialized using an initializer list. In the following example, "t" is a const data member of the Test class and is initialized using this method. The reason for initializing a const data member in the initializer list is that no separate memory is allocated for it; instead, it is folded into the symbol table. Therefore, it is necessary to initialize it in the initializer list.
Additionally, since this is a copy constructor, we do not need to call the assignment operator. This approach helps us avoid an extra operation.
#include<iostream>
using namespace std;
class Test {
const int t;
public:
Test(int t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
Test t1(10);
cout<<t1.getT();
return 0;
}
/* OUTPUT:
10
*/
2) For initialization of reference members:
Reference members should be initialized using an initializer list. In the following example, "t" is a reference member of the Test class and is initialized using this initializer list.
// Initialization of reference data members
#include<iostream>
using namespace std;
class Test {
int &t;
public:
Test(int &t):t(t) {} //Initializer list must be used
int getT() { return t; }
};
int main() {
int x = 20;
Test t1(x);
cout<<t1.getT()<<endl;
x = 30;
cout<<t1.getT()<<endl;
return 0;
}
/* OUTPUT:
20
30
*/
3) For initialization of member objects that do not have default constructor:
In the following example, an object “a” of class “A” is data member of class “B”, and “A” doesn’t have a default constructor. Initializer List must be used to initialize “a”.
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int );
};
A::A(int arg) {
i = arg;
cout << "A's Constructor called: Value of i: " << i << endl;
}
// Class B contains an object of A
class B {
A a;
public:
B(int );
};
B::B(int x):a(x) { //Initializer list must be used
cout << "B's Constructor called";
}
int main() {
B obj(10);
return 0;
}
/* OUTPUT:
A's Constructor called: Value of i: 10
B's Constructor called
*/
If class A has both default and parameterized constructors, then the Initializer List is not necessary if we want to initialize “a” using the default constructor, but it is necessary to initialize “a” using the parameterized constructor.
4) For initialization of base class members :
Like point 3, the parameterized constructor of the base class can only be called using the Initializer List.
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int );
};
A::A(int arg) {
i = arg;
cout << "A's Constructor called: Value of i: " << i << endl;
}
// Class B is derived from A
class B: A {
public:
B(int );
};
B::B(int x):A(x) { //Initializer list must be used
cout << "B's Constructor called";
}
int main() {
B obj(10);
return 0;
}
5) When the constructor’s parameter name is the same as the data member:
If the constructor’s parameter name is the same as the data member name then the data member must be initialized either using this pointer or Initializer List. In the following example, both the member name and parameter name for A() is “i”.
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int );
int getI() const { return i; }
};
A::A(int i):i(i) { } // Either Initializer list or this pointer must be used
/* The above constructor can also be written as
A::A(int i) {
this->i = i;
}
*/
int main() {
A a(10);
cout<<a.getI();
return 0;
}
/* OUTPUT:
10
*/
6) For Performance reasons:
It is better to initialize all class variables in the Initializer List instead of assigning values inside the body. Consider the following example:
// 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
1. Type’s constructor is called first for “a”.
2. The assignment operator of “Type” is called inside the body of the MyClass() constructor to assign
variable = a;
3. And then finally destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with the MyClass() constructor with the 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:
1. The copy constructor of the “Type” class is called to initialize: variable(a). The arguments in the initializer list are used to copy the construct “variable” directly.
2. The destructor of “Type” is called for “a” since it goes out of scope.
As we can see from this example if we use assignment inside constructor body there are three function calls: constructor + destructor + one addition assignment operator call. And if we use Initializer List there are only two function calls: copy constructor + destructor call. See this post for a running example on this point.
Comments
Post a Comment