C + + Initialization list
What is a list of initialization
Unlike other functions, constructors can have initialization lists, in addition to names, argument lists, and function bodies, which begin with a colon, followed by a series of comma-delimited initialization fields. In C + +, the only difference between struct and class is that the default access is different, and here we do not consider the problem of accessibility, so the following code is demonstrated with struct.
struct Foo
{
string name;
int id;
Foo (string s, int i): name (s), id (i) {}; Initialize list
};
Two execution stages of a constructor
The execution of a constructor can be divided into two phases, initialization phase and calculation phase, initialization phase prior to the calculation stage.
Initialization phase
The members of all class types (classes type) are initialized during the initialization phase, even if the member does not appear in the constructor's initialization list.
Calculation phase
Typically used to perform assignment operations within the body of a constructor, the following code defines two structures, where Test1 has constructors, copy constructors, and assignment operators to facilitate viewing of the results. Test2 is a test class that takes a Test1 object as a member, and we look at how the Test2 constructor executes.
struct Test1
{
Test1 ()//parameterless constructor
{
cout << "construct Test1" << Endl;
}
Test1 (const test1& T1)//copy constructor
{
cout << "copy constructor for Test1" << Endl;
This->a = t1.a;
}
test1& operator = (const test1& t1)//assignment operator
{
cout << "assignment for Test1" << Endl;
this->a = t1.a;
return *this;
}
int A;
};
struct Test2
{
Test1 test1;
Test2 (Test1 &t1)
{
test1 = t1;
}
};
Calling code
Output
Explain that the first line of output corresponds to the first line in the calling code and constructs a Test1 object. The second line of output corresponds to the code in the Test2 constructor and initializes the object test1 with the default constructor, which is the so-called initialization phase. The third line outputs the assignment operator corresponding to the TEST1, performing assignment operations on Test1, which is called the computational phase.
Why use the initialization list
There are two ways to initialize members of a class, one is to use an initialization list, and the other is to perform assignment operations in the constructor body. Using an initialization list is primarily based on performance issues, and for built-in types such as int, float, and so on, initializing the class table and initializing the difference in the constructor body is not very significant, but for class types it is best to use an initialization list. From the test above, it is very efficient to use the initialization list to call the default constructor one less time for data-intensive classes. Also look at the example above, we use the initialization list to implement the Test2 constructor
struct Test2
{
Test1 test1;
Test2 (Test1 &t1): test1 (t1) {}
}
Using the same calling code, the output is as follows.
The first line of output corresponds to the first line of the calling code. The second line outputs the initialization list corresponding to the TEST2, directly calling the copy constructor to initialize the Test1, eliminating the process of invoking the default constructor. So a good rule is to use the initialization list whenever possible using the initialization list.
Which things must be placed in the initialization list
In addition to performance issues, there are times when initialization lists are essential, and you must use an initialization list in the following situations
- Constant member, because a constant can only initialize a value that cannot be assigned, so it must be placed in the initialization list
- Reference type, the reference must be initialized at the time of definition, and cannot be assignable, so write it in the initialization list
- A class type that does not have a default constructor, because using an initialization list can be initialized without invoking the default constructor, but directly by calling the copy constructor.
For classes that do not have a default constructor, let's look at an example.
struct Test1
{
Test1 (int a): I (a) {}
int i;
};
struct Test2
{
Test1 test1;
Test2 (Test1 &t1)
{
test1 = t1;
}
};
The above code cannot be compiled because the Test1 test1 in the Test2 class; The default constructor needs to be invoked, but the Test1 class has no parameterless constructor, but because Test1 does not have a default constructor, compile the error. The correct code is as follows, using an initialization list instead of an assignment operation.
struct Test2
{
Test1 test1;
Test2 (Test1 &t1): test1 (t1) {}
}
Initialization order for member variables
Members are initialized according to the order in which they appear in the class, rather than in the order in which they appear in the initialization list, looking at the code.
struct foo
{
int i;
Int J;
Foo (int x): I (x), J (i) {}; OK, first initialize I, then initialize J
};
And look at the code below.
struct foo
{
int i;
Int J;
Foo (int x): j (x), I (j) {}//I value undefined
};
The value of I here is undefined, although J appears in the initialization list in front of I, but I is preceded by J, so I is initialized first, but I is initialized by J, this time J has not been initialized, so the value of I is undefined. So, a good habit is to initialize in the order of the members defined.
Thank you for reading, I hope to help you, thank you for your support for this site!