C + + object Model-member initialization list (chap. II)

Source: Internet
Author: User

2.4 Member Initialization list (Member initialization list) when writing a constructor for a class, it is possiblesets the initial value of a class member, either by initializing the member initialization list, or by initializing within the constructor, in addition to four cases, in fact, any choice is similar.
In this section, it is important to clarify when to use the initialization list to make sense, and then explain what the real action is inside the initialization list, and then look at some subtle pitfalls.
in the following cases, in order for the program to be compiled smoothly, You must use the member initialization list (cannot be initialized within the constructor):
1. When initializing a referenced member
2. When initializing a constant member (const member)
3. When a constructor for a base class is called, and it has a set of parameters
4. When a constructor for a member class object is called, and it has a set of parameters

In these four cases, the program can be compiled and executed correctly, but it is inefficient. For example:
Class Word {private:    String _name;    int _cnt;public:    //No error, but too naive    Word () {        _name = 0;        _cnt = 0;    }};
Here, the word constructor produces a temporary string object, initializes it, assigns the temporary object to _name with an assignment operator, and then destroys the temporary object. The following are the possible internal expansion results of the constructor:
C + + pseudo-code Word::word (/* This pointer goes here */) {    //invokes the default constructor _name of string    . String::string ();    The resulting temporary object,    String temp = string (0);    "Memberwise" to copy _name    _name. string::operator= (temp);    Destroys temporary object    temp. String::~string ();    _cnt = 0;}
The program code is reviewed and revised repeatedly to get a significantly more efficient implementation method:
Better way Word::word: _name (0) {    _cnt = 0;}    It will be expanded to look like this://C + + pseudo code Word::word (/* This pointer goes here */) {    //call string (int) constructor    _name. String::string (0);    _cnt = 0;}
By the way, traps are most likely to occur in this form of template code:
Template <class Type>foo<type>::foo (type T) {    //may or may not be a good idea//    depending on the true type of type    _t = 0;}
This leads some programmers to be very aggressive in insisting that all member initialization operations must be done in the member initialization list, even if a well-behaved member such as _CNT
Stick to this style of code Word::word ()    : _cnt (0), _name (0) {}
What exactly happened in the member initialization list? Many people are confused about the syntax of list and mistakenly think that it is a set of function calls, of course not!
The compiler will manipulate the initialization list to insert initialization actions within the constructor in an appropriate order, and before any explicit user code。 For example, the previous word constructor was expanded to:
C + + pseudo code Word::word (/* This pointer goes here */) {    _name. String::string (0);    _cnt = 0;}
It looks very much like specifying the value of _cnt in the constructor, in fact, there are some subtle places to note:The order of items in a list is determined by the order in which the members in the class are declared, not by the order in which they are sorted in the initialization list .。 In this example of the word class, _name is declared before _cnt, so it is initialized earlier than _cnt.
The difference between the initialization order and the order of items in the initialization list can lead to unexpected risks:
Class X {private:    int i;    int j;public:    X (int val)        : J (Val), I (j)    {}};
The above program code seems to set J to the initial value of Val, and then set I to the initial value of J. However, because of the order of declarations, I (j) in the initialization list is executed earlier than J (Val). J does not initially have an initial value, so the execution result of I (j) causes I to be initialized to an unpredictable value.
The difficulty with this bug is that it is not easily observable and the compiler should issue a warning message. But there is currently only one compiler (g++) to do this. (The test VS2010 did not give a warning message, Lippman did cow break, 2000 questions, VS10 did not solve), X x (0), and then output the value of the i,j of X, as shown in the result:

The value of I is not normal and J value is normal. No warning message was given in VS10.
And there's an interesting question,will the items in the initialization list be inserted into the constructor and continue to save the declaration order?In other words, known:
An interesting question x::x (int val): J (Val) {    i = j;}
Will the initialization order of J be inserted before or after the explicit user assignment operation (i=j)?
if the declaration order continues to be saved, this code can be problematic (because I is initialized first and then J is initialized). In fact, this code is correct because the item that initializes the list is inserted before the explicit user code.
Another common question is whether you can invoke a member function to set the initial value of a member, as shown below:
X::xfoo () called x::x (int val): I (Xfoo (Val)), J (Val) {}
where Xfoo () is a member function of x, the answer is yes. However, it is preferable to use "one member that exists in a constructor" instead of "Member in Member initialization List" to set an initial value for another member. Unsure how high the Xfoo () dependence on X object is, If you put Xfoo () in the constructor body, you can give a definite answer to "which member is set as the initial value at Xfoo () execution."
The use of member functions is legal because the this pointer associated with this object has been constructed, and the constructor is roughly expanded to:
Constructor The result of the expansion x::x (/* This pointer, */int val) {    i = This->xfoo (val);    j = Val;}
What if a derived class member function is called and its return value is treated as a parameter of the base class constructor?
Can I call Foobar::fval ()? class Foobar:public X {private:    int _fval;public:    int fval () {return _fval;}             Derived class member function    FooBar (int val): _fval (Val), X (FVal ())    //FVal () as a base class constructor parameter 
   
    {}};
   
Here's what it might do to expand:
C + + pseudo code Foobar::foobar (/* This pointer goes here */) {    x::x (this, this->fval ());    _fval = val;}
It's really not a good idea.

Summarize the compiler processes the initialization list one by one and may reorder it to reflect the declaration order of the member, inserting some code into the constructor body, and inserting it before any explicit user code.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

C + + object Model-member initialization list (chap. II)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.