I'm observing strange behaviour with clang++ (3.5-1ubuntu1). If virtual inheritance is used, the copy constructor of the 'Base' class appears to be skipped. Please see the sample and results below.
The complicated inheritance hierarchy is needed, it comes from an application using std streams and streambufs.
Questions:
- What should the value of foo.x be after foo's initialisation?
- Why does the result change when normal instead of virtual inheritance is used? Notice that there's no multiple inheritance involved, so I'd expect no difference.
- Am I invoking undefined behavior? If yes, where? If yes, could the compiler warn about it?
#include <iostream>
struct Base {
int x;
Base() : x(0) {}
Base(Base const& other) : x(other.x) {
std::cout << "Base::Base(Base const&)" << std::endl;
}
};
// If virtual is removed, it works.
struct Derived1 : virtual Base {
// struct Derived1 : Base {
Derived1(Derived1&& other) : Base(static_cast<const Base&>(other)) {
std::cout << "MOVE constructor: other.x = " << other.x
<< ", this->x = " << x << std::endl;
}
Derived1() {
x = 4711;
std::cout << "DEFAULT constructor: x = " << x << std::endl;
}
} ;
template< typename B >
struct Derived2 : B {
// Deliberately invoke move constructor
Derived2() : B( B() ) { }
} ;
int main() {
Derived2<Derived1> foo ;
// Expected: 4711, actual: 0
std::cout << "foo.x = " << foo.x << std::endl;
std::cout << "sizeof(Base) = " << sizeof(Base) << std::endl;
std::cout << "sizeof(Derived1) = " << sizeof(Derived1) << std::endl;
std::cout << "sizeof(foo) = " << sizeof(foo) << std::endl;
// As expected, all addresses are equal, regardless whether virtual
// inheritance is used or not.
std::cout << "&Derived2::x = " << &foo.x << std::endl;
std::cout << "&Derived1::x = " << &static_cast<Derived1 const&>(foo).x << std::endl;
std::cout << "&Base::x = " << &static_cast<Base const&>(foo).x << std::endl;
}
The result I'm getting:
DEFAULT constructor: x = 4711
MOVE constructor: other.x = 4711, this->x = 0
foo.x = 0
sizeof(Base) = 4
sizeof(Derived1) = 16
sizeof(foo) = 16
&Derived2::x = 0x7fff7a445338
&Derived1::x = 0x7fff7a445338
&Base::x = 0x7fff7a445338