使用虚拟继承和委托构造函数在构造函数中崩溃
Crash in constructor with using virtual inheritance and delegating constructors
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;
}
我遇到带有上述代码的 MSVC 2013 编译器崩溃。当使用 GCC 4.7.2 编译时,它运行而不会崩溃。类的层次结构如下所示。
D
/
D1 D2
| |
B
/
A
这是 MS 编译器中的错误还是我在代码中犯了错误?
快速检查 MSVC++ 2013 编译器生成的程序集代码显示,从B::B(int)
到B()
的委托调用不正确。这是编译器中的一个错误。
MSVC++构造函数有一个隐藏的布尔参数,该参数告诉构造函数它是在构造派生最多的对象(true
(还是嵌入的基子对象(false
(。在此示例中,只有A::A()
应接收此隐藏参数中的true
,而所有较低级别的构造函数调用都应接收false
。然而,当从B::B(int)
调用B()
时,编译器无条件地传递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()`
...
在正确生成的代码中,当编译器进行委托构造函数调用时,它应该传递从调用方收到的参数值,而不是硬编码的1
。
在此示例中,从A::A()
进行的直接子构造函数调用的顺序如下:1(公共虚拟基D
,2(基B
,3(基D1
。
根据语言规则,在这种情况下,B
的构造函数和D1
的构造函数不应该构造它们的虚拟基D
。基D
此时已经由派生最多的对象A
构造。这正是由该隐藏布尔参数控制的内容。然而,当从B::B(int)
调用B::B()
时,编译器传递一个不正确的参数值(硬编码1
(,这导致B::B()
错误地假设它构造了一个派生最多的对象。这反过来又使B
重建了共同的虚拟基础D
。这种重建覆盖了A::A()
已经进行的正确施工的结果。后来这会导致崩溃。
据我所知,您的代码示例应该可以工作。
但是,顺便说一句,构造函数委托可能被视为不好的做法。 你应该有一个完全定义的构造函数,所有定义较少的构造函数都委托给该构造函数,而不是相反。 例如:
struct B : public D2
{
B() : B(0) { }
B(int val) { }
void m() const { }
};
- 复制赋值构造函数中的aligned_alloc内存块在释放时崩溃
- 如果构造函数从调用到 std::make_shared 崩溃,GDB 是否可以显示崩溃的详细信息
- 动态数组在构造函数处崩溃
- 程序崩溃在复制构造函数上
- 崩溃:分段故障:增强序列化加载 - 用null调用构造函数
- 为什么在复制构造函数中分配联合成员会崩溃
- 在构造函数因未初始化成员而崩溃之前调用的C++函数
- C++初始化复制构造函数中的列表赋值,并在复制构造函数中崩溃
- 使用Invalid_pointer移动无限制联合崩溃的构造函数
- C :复制构造函数崩溃
- QTimer在构造函数或静态中创建时会崩溃
- 在构造函数[C ]中的FP分配上崩溃
- 双向链表复制构造函数和程序崩溃
- 复制构造函数动机 - 为什么我的程序不崩溃?
- 调用构造函数后程序崩溃
- 为什么我的C++程序在使用构造函数时会崩溃
- 如何确保当无效字符串作为参数传递时posix_time_zone构造函数不会崩溃
- 从实例化为静态本地崩溃的类的构造函数调用QPluginLoader::staticInstance
- C ++使用框架崩溃,构造函数错误
- 使用成员编写移动构造函数的正确方法unique_ptr(崩溃)