Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
219 views
in Technique[技术] by (71.8m points)

c++ - Initialization list bug in gcc?

Consider the following code, where B is a virtual base class inherited by D through B1 and B2:

#include <iostream>

class B
{
protected:
    int x;

protected:

    B(int x) : x{x}{std::cout << x << std::endl;}
};

class B1 : virtual public B
{
protected:

    B1() : B(0){}
};

class B2 : virtual public B
{
protected:

    B2() : B(10){}
};

class D : public B1, public B2
{
public:

    D() : B(99), B1(), B2() {}
    void print() {std::cout << "Final: " << x << std::endl;}
};

int main() {
    D d;
    d.print();
    return 0;
}

See working example here. I use outputs in B's constructor and after D has been completely constructed to keep track of what's going on. Everything works fine, when I compile the above example with g++-4.8.1. It prints

99
Final: 99

because Bs constructor is called once from the most derived class (D) and that also determines the final value of x.

Now comes the strange part: If I change the line

D() : B(99), B1(), B2() {}

to the new uniform initialization syntax, i.e.

D() : B{99}, B1{}, B2{} {}

strange things happen. For one, it doesn't compile anymore, with the error

prog.cpp: In constructor ‘D::D()’:
prog.cpp:17:5: error: ‘B1::B1()’ is protected
     B1() : B(0){}
     ^
prog.cpp:31:27: error: within this context
     D() : B{99}, B1{}, B2{} {}

(and the same for B2, see here) which doesn't make sense because I am using it in a derived class, so protected should be fine. If I correct for that and make the constructors of B1 and B2 public instead of protected, everything gets totally messed up (see here), as the output becomes

99
0
10
Final: 10

So, in fact, the parts of B1s and B2s constructors that initialize B are still executed and even change the value of x. This should not be the case for virtual inheritance. And remember, the only things I have changed are

  • public instead of protected constructors in B1 and B2
  • use classname{} syntax in member initialization list of D instead of classname().

I cannot believe such a basic thing goes wrong in gcc. But I tested it with clang on my local machine and there, all three cases compile and run as intended (i.e. like the first example above). If it's not a bug, can someone please point me to what I am missing?

EDIT: My first search somehow didn't bring it up, but now I found this other question, showing at least the protected/public error. However, this was gcc-4.7, so I would have expected it to be dealt with in gcc-4.8. So, should I conclude initializer lists are just fundamentally messed up in gcc!?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't know if it's too late to answer this, but your code compiles fine in GCC 4.9.2!

~$g++ -std=c++11 test.cpp 
~$./a.out 
99
Final: 99

~$gcc --version
gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...