Skip to main content

C++ initializer list order in a constructor matters?

This is a computer related article, and about THE hardest language, C++. So, I think the audience is again limited.

gcc's -Wall option sometimes gives a warning as the order of initializer list in the constructor is wrong. For example,

% g++ -Wall initializer_list.cc
initializer_list.cc: In constructor 'InitializerListTest::InitializerListTest()':
initializer_list.cc:30: warning: 'InitializerListTest::d_j' will be initialized after
initializer_list.cc:29: warning: 'int InitializerListTest::d_i'
initializer_list.cc:7: warning: when initialized here.

This warning said that the order of initializer list in the constructor and the member variables declaration order are different. The following code is such an example.

---
#include

class InitializerListTest {
public:
/// constructor
InitializerListTest() :
d_j(123), // j = 123;
d_i(d_j - 1) // i = j - 1;
{
// empty
}
/// print out
void print()
{
std::cout << "i = " << d_i << ", j = " << d_j << std::endl;
}

private:
/// i, j
int d_i;
int d_j;
};

int main()
{
InitializerListTest ilt;
ilt.print();
return 0;
}
---

This warning pointed out that the member initialization order does not related with the order of initializer list in C++. In the C++ book 3rd edition by Stroustrup, Section 10.4.6 Class Objects as Members describes this as "The constructors are called in the order in which they are declared in the class rather than the order in which they appear in the initializer list. To avoid confusion, it is best to specify the initializers in declaration order." This is the meaning of the warning. In the above sample code, the initializer list is

d_j(123),
d_i(d_j - 1).

This looks like the following code,

d_j = 123;
d_i = (d_j - 1);.

But, actually, it is

d_i = (d_j - 1);
d_j = 123;.

Therefore, the value of d_i is undefined. In my environment, the execution result is

i = 32766, j = 123.


Since this is a source of the confusion, I agree the C++ book and gcc warnings. But, the real problem comes from the initialization depends on other member initialization. In such case, I avoid to initialize the member in the initialization list, rather do in the constructor body. It would be more accurate that if the warning detects the dependency between the initializer list.

The answer of the title of this article, "C++ initializer list order in a constructor matters?", would be Yes. By the way, Lisp has let and let* for the block local variable initialization. We can initialize the let function's element in Lisp, and let* is the sequential version, which defines the order of initialization. C++'s initializer list is an implicit version of the let*.

I think it is a bit unnatural in C++ since C++ has only implicit let*, which is based on sequential model. C++'s design is usually tend to execution time optimization. But this definition lead us to make it hard to understand and to be potentially slower. (Or is it a nature of C++?)

Comments

Dividend Lover said…
good explaination thanks

Popular posts from this blog

Why parallelogram area is |ad-bc|?

Here is my question. The area of parallelogram is the difference of these two rectangles (red rectangle - blue rectangle). This is not intuitive for me. If you also think it is not so intuitive, you might interested in my slides. I try to explain this for hight school students. Slides:  A bit intuitive (for me) explanation of area of parallelogram  (to my site, external link) . 

Geometric Multiplicity: eignvectors (2)

If eigenvectors of a matrix A are independent, it is a happy property. Because the matrix A can be diagonalized with a matrix S that column vectors are eigenvectors of A . For example, Why this is a happy property of A? Because I can find A's power easily. A^{10} is not a big deal. Because Λ is a diagonal matrix and power of a diagonal matrix is quite simple. A^{10} = SΛ^{10} S^{-1} Then, why if I want to compute power of A ? That is the same reason to find eigenvectors. Eigenvectors are a basis of a matrix. A matrix can be represented by a single scalar. I repeat this again. This is the happy point, a matrix becomes a scalar. What can be simpler than a scalar value. But, this is only possible when the matrix S's columns are independent. Because S^{-1} must be exist. Now I come back to my first question. Is the λ's multiplicity related with the number of eigenvectors? This time I found this has the name. Geometric multiplicity (GM): the number of in...

Tezuka Osamu's Black Jack, "Shrinking"

I like several novel authors. My first favorite author is probably Teduka, Osamu. I still love him. The list grows by adding Hoshi, Shinichi, Agatha Christie, Hermann Hesse, and so forth. My first favorite article of Tezuka was Atom as most of the (boy's) Tezuka fans did. But my favorite is Black Jack. I try to summarize one story, it is still quite vivid in my memory. I first read this story when I was 13 - 15 years old. I re-read it at least several times since Black Jack is composed of many short episodes. The title should be "ちぢむ (SHRINKING)" or it might be "縮む(Shrinking)". (It is not so convenient to translate this to English, since English does not have a system to say the exact same word in several ways. So I just simulate it with capital letters.) Black Jack is a genius surgeon, but he does not have the license. In short, his medical activity is illegal. His skill is top level in the world, but, the fee is also out-of-law expensive. In the story ...