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.