【发布时间】:2016-11-24 01:36:12
【问题描述】:
我有一些代码。它不起作用。
首先,您会看到这个示例代码 sn-p 并思考“为什么?”但相信我:这是有原因的。
代码如下:
class LinkedListNode
// blaa
{
public:
LinkedListNode ( void* p )
{
// blaa
}
} ;
template <typename T>
class InheritAndLinkList
: public virtual T
, public LinkedListNode
{
public:
InheritAndLinkList ()
: LinkedListNode ( static_cast<void*>(static_cast<T*>(this)) ) // an exception occurs here when ..... (scroll down)
{ }
} ;
template <typename T>
class Implements
: public virtual InheritAndLinkList<T>
{ } ;
class A
{
public:
virtual void goA () =0 ;
} ;
class B
: public Implements<A>
{
public:
virtual void goB () =0 ;
} ;
class MyClass
: public Implements<B>
{
public:
virtual void goA ()
{
// blaa
}
virtual void goB ()
{
// blaa
}
} ;
int main ( ... )
{
MyClass * p = new MyClass () ; // ..... This line executes
p->goA() ;
p->goB() ;
return 0 ;
}
具体错误是,在构造时,表达式static_cast<T*>(this) 会导致分段错误......当使用英特尔C++ 编译器时。这已经在许多版本的 GCC、LLVM、MS Visual Studio 等上运行了多年。现在 ICPC 让它死了。
我相信这是一件完全正确的事情。当这条线被调用时,T 已经被构建并且应该可以有效使用......除非 C++ 规范中还有其他奇怪的东西。
将static_cast 放入构造函数主体(并更改其超级以匹配)使其避免此段错误。
所以我的问题是:规范在哪里说这个 [static cast] 是/不安全的?
【问题讨论】:
-
您遇到了什么异常?这在我的系统上编译并运行良好(g++)
-
详细说明 - 你这里的代码看起来完全没问题(虽然继承图花了我一段时间才画出^_^),所以我怀疑还有其他事情发生。此外,这个示例是否足以导致崩溃(例如,我是否应该期望它在运行时崩溃?)
-
不清楚为什么需要所有这些虚拟继承——实际上并没有菱形的层次结构。有一个类在继承点阵中出现了两次 -
LinkedListNode- 但这正是您不虚拟继承的类,因此最终在MyClass中有两个副本。跨度> -
@curiousguy "[class.base.init]/16 可以为正在构建的对象调用成员函数(包括虚成员函数,10.3)。类似地,一个对象under construction 可以是
typeid运算符 (5.2.8) 或dynamic_cast(5.2.7) 的操作数。但是,如果这些操作在 ctor-initializer 中执行(或在从 ctor-initializer) 直接或间接调用的函数中,在基类的所有 mem-initializer 完成之前,操作的结果是未定义的。"但是 OP 的代码没有执行三个禁止的操作。 -
@iAdjunct 同样的例子还说
D(this)是UB。如果从E*到A*的演员阵容纯粹是静态的,那为什么会这样?在任何情况下,标准文本都没有在您试图做出的“动态”和“静态”之间做出区分。它描述了在什么条件下可以将派生指针转换为基指针。如果您想争辩本段不适用,您必须准确解释违反了哪些条件以及如何违反(特别是因为您自己要求提供语言律师的答案)。
标签: c++ constructor language-lawyer lifetime virtual-inheritance