eXX*_*XX2 8 c++ virtual-inheritance visual-c++ c++11 delegating-constructor
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;
}
Run Code Online (Sandbox Code Playgroud)
使用上面的代码我遇到MSVC 2013编译器崩溃.使用GCC 4.7.2编译时,它运行时没有崩溃.类的层次结构如下所示.
D
/ \
D1 D2
| |
\ B
\ /
A
Run Code Online (Sandbox Code Playgroud)
这是MS编译器中的一个错误,或者我在代码中犯了错误?
通过MSVC++ 2013编译器生成的汇编代码的快速检查表明,从委派呼叫B::B(int)到B()被不正确地制造.这是编译器中的一个错误.
MSVC++构造函数有一个隐藏的布尔参数,告诉构造函数它是构造一个派生程度最大的对象(true)还是嵌入式基础子对象(false).在这个例子中,只A::A()应该true在这个隐藏参数中接收,而所有低级构造函数调用都应该接收false.但是,当B()调用from时B::B(int),编译器无条件地传递1(true)作为隐藏参数.这是不正确的.
; 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()`
...
Run Code Online (Sandbox Code Playgroud)
在编译器进行委托构造函数调用时正确生成的代码中,它应该传递从调用者接收的参数值,而不是硬编码1.
A::A()在此示例中进行的立即子构造函数调用的顺序如下:1)公共虚拟基础D,2)基础B,3)基础D1.
根据语言规则,在这种情况下,构造函数B和构造函数D1不应构造其虚拟基础D.Base D已经由最派生的对象在那时构建A.这正是由隐藏的布尔参数控制的内容.但是,当B::B()调用from时B::B(int),编译器会传递一个不正确的参数值(硬编码1),这会导致B::B()错误地认为它构造了一个派生程度最高的对象.这转而B重新构建了公共虚拟基础D.这种重建优先于已经完成的正确施工的结果A::A().后来这会导致崩溃.
小智 0
据我所知,您的代码示例应该可以工作。
不过,顺便说一句,您的构造函数委托可能被认为是不好的做法。您应该有一个完全定义的构造函数,所有较少定义的构造函数都委托给该构造函数,而不是相反。例如:
struct B : public D2
{
B() : B(0) { }
B(int val) { }
void m() const { }
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
510 次 |
| 最近记录: |