struct D
{
virtual void m() const = 0;
};
struct D1 : public virtual D { };
struct D2 : public virtual D { };
struct B : public D2
{
B() { }
B(int val) : B() { }
void m() const { }
};
struct A : public B, public D1
{
A() : B(0) { }
};
int main()
{
A a;
return 0;
}
I get crash with MSVC 2013 compiler with above code. It runs without crash when compiled with GCC 4.7.2. Hierarchy of classes is depicted below.
D
/ \
D1 D2
| |
\ B
\ /
A
This is a bug in MS compiler or I made a mistake in the code?
A quick examination of the assembly code generated by MSVC++ 2013 compiler shows that the delegated call from B::B(int)
to B()
is made incorrectly. It is a bug in the compiler.
MSVC++ constructors have a hidden boolean parameter that tells the constructor whether it is constructing a most derived object (true
) or an embedded base subobject (false
). In this example, only A::A()
should receive true
in this hidden parameter, while all lower-level constructor calls should receive false
. However, when B()
is called from B::B(int)
, the compiler unconditionally passes 1
(true
) as that hidden parameter. This is incorrect.
; Code for `B::B(int)`
...
00F05223 push 1 ; <- this is the problem
00F05225 mov ecx,dword ptr [this]
00F05228 call B::B (0F010F0h) ; <- call to `B::B()`
...
In the the properly generated code when the compiler makes a delegated constructor call, it should pass along the parameter value received from the caller, not a hardcoded 1
.
The order of immediate sub-constructor calls made from A::A()
in this example is as follows: 1) common virtual base D
, 2) base B
, 3) base D1
.
Per rules of the language, in this case the constructor of B
and the constructor of D1
is not supposed to construct their virtual base D
. Base D
is already constructed at that point by the most derived object A
. This is exactly what is controlled by that hidden boolean parameter. However, when B::B()
is called from B::B(int)
, the compiler passes an incorrect parameter value (that hardcoded 1
), which caused B::B()
to incorrectly assume that it constructing a most derived object. This is turn makes B
re-construct the common virtual base D
. This re-construction overrides the results of the proper construction already made by A::A()
. Later this causes the crash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With