在什么情况/情况下,dynamic_cast <>可能会失败?
在修复巨大代码库中的错误时,我观察到一种奇怪的情况,其中动态类型的引用从原始Derived
类型更改为Base
类型!我提供了最少的代码来说明问题:在什么情况/情况下,dynamic_cast <>可能会失败?
funcptr
是一个函数指针(void (*)(SomeClass&)
)。 funcptr
可以指向如此多的功能,并且它们有自己的呼叫流程,因此很难调试。
很奇怪的是,在调用函数指针之后,派生类型ref
从Derived
更改为Base
。为了缓解我的工作,我怀疑对象从Derived
切片到Base
,所以我制作了~Base()
纯virtual
并重新编译了整个源代码。但是没有编译器错误,这意味着没有声明Base
的对象。
潜在的原因是什么,ref
Derived
的动态类型更改为Base
,并且dynamic_cast
以后失败?
我不相信上面的代码是真的,因为代码示例没有编译!您不能将由dynamic_cast<Base*>(&ref)
产生的Base*
隐式转换为Derived*
。
这就是说,并假设typeid()
的输出实际上是正确的,有几个可行的解释引用改变的类型ID。所有这些都以某种形式或另一种形式指示程序中的错误:
- 被调用的函数破坏了对象,例如通过调用
dynamics_cast<Base*>(obj.pVoid)->~Base()
的道德等价物。 - 被调用的函数在
obj.pVoid
使用放置new
指向的地址构造一个新的对象,即类似这样的:new(obj.pVoid) Base()
。 - 某物正在覆盖内存,导致在参考位置留下一个
Base
对象。 - 可能有更多的理由...
就个人而言,我会赌上第二种情况是情况下,即一个对象被构建到的位置。显然,没有看到被调用的函数,这是不可能的。
这是一个错字,我编辑过'dynamic_cast
dynamic_cast
(如果指针)可以返回0
如果转换不明确。举例说明:
class O {…};
class A : public virtual O {…};
class B : public A {…};
class C : public A {…};
class D : public B, public C {…};
void f(O& p) {
A* const a(dynamic_cast<A*>(&p));
}
void g() {
D d;
f(d);
}
在我的具体情况下,dynamic_cast<>
失败的原因是由于delete
提前引用!
一旦指针或引用是delete
+破坏,然后任何企图将其向下到原来的类型将导致进入“未定义行为”区。在我的情况下,dynamic_cast<>
失败。
void foo (Base &ref)
{
SomeClass obj;
obj.pVoid = &ref;
(*funcptr)(obj); // ----> delete (Base*)(obj.pVoid); in one of the callbacks
Derived *p = dynamic_cast<Derived*>(&ref); // fails => "p = 0"
}
如果typeid(ref)在调用之后是基础的,那么函数会与对象混淆。你传递一个指向对象的指针,所以在整个对象上写入随机的东西是很容易的。 – 2012-02-11 08:54:47
@LokiAstari,虽然这段代码已经稳定好几年了,但你告诉我的是主要的嫌疑人。 'pVoid'可能会搞乱它,但我必须看看它在什么情况下发生。在此之前,我想检查一下,如果我遗漏了任何可能会将动态类型更改为静态类型以供参考的小事。 – iammilind 2012-02-11 09:11:40