在什么情况/情况下,dynamic_cast <>可能会失败?

在什么情况/情况下,dynamic_cast <>可能会失败?

问题描述:

在修复巨大代码库中的错误时,我观察到一种奇怪的情况,其中动态类型的引用从原始Derived类型更改为Base类型!我提供了最少的代码来说明问题:在什么情况/情况下,dynamic_cast <>可能会失败?

​​

funcptr是一个函数指针(void (*)(SomeClass&))。 funcptr可以指向如此多的功能,并且它们有自己的呼叫流程,因此很难调试。

很奇怪的是,在调用函数指针之后,派生类型refDerived更改为Base。为了缓解我的工作,我怀疑对象从Derived切片到Base,所以我制作了~Base()virtual并重新编译了整个源代码。但是没有编译器错误,这意味着没有声明Base的对象。

潜在的原因是什么,refDerived的动态类型更改为Base,并且dynamic_cast以后失败?

+2

如果typeid(ref)在调用之后是基础的,那么函数会与对象混淆。你传递一个指向对象的指针,所以在整个对象上写入随机的东西是很容易的。 – 2012-02-11 08:54:47

+0

@LokiAstari,虽然这段代码已经稳定好几年了,但你告诉我的是主要的嫌疑人。 'pVoid'可能会搞乱它,但我必须看看它在什么情况下发生。在此之前,我想检查一下,如果我遗漏了任何可能会将动态类型更改为静态类型以供参考的小事。 – iammilind 2012-02-11 09:11:40

我不相信上面的代码是真的,因为代码示例没有编译!您不能将由dynamic_cast<Base*>(&ref)产生的Base*隐式转换为Derived*

这就是说,并假设typeid()的输出实际上是正确的,有几个可行的解释引用改变的类型ID。所有这些都以某种形式或另一种形式指示程序中的错误:

  1. 被调用的函数破坏了对象,例如通过调用dynamics_cast<Base*>(obj.pVoid)->~Base()的道德等价物。
  2. 被调用的函数在obj.pVoid使用放置new指向的地址构造一个新的对象,即类似这样的:new(obj.pVoid) Base()
  3. 某物正在覆盖内存,导致在参考位置留下一个Base对象。
  4. 可能有更多的理由...

就个人而言,我会赌上第二种情况是情况下,即一个对象被构建到的位置。显然,没有看到被调用的函数,这是不可能的。

+0

这是一个错字,我编辑过'dynamic_cast (&ref)'。原因(2)可能是不可能的,因为我已经提到过这个问题。我已经使'Base ::〜Base()'成为纯'virtual'并重新编译了代码,但是没有编译器错误。这意味着没有对象创建'Base'类。 – iammilind 2012-02-11 13:37:37

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); 
} 
+0

在这种情况下没有多重继承。此外,即使它会在那里,在我的情况下,它不会影响。因为在函数调用之前,'Base&ref'的动态类型是'Derived'。所以它应该保持原样。 – iammilind 2012-02-11 09:14:17

+0

@iammilind好的。如果它帮助别人,我会放弃它。认为:也许你可以添加一个(或多个)参数的虚拟调用,并逐步查看实际执行的内容以帮助确定类型(或者暴露内存碎片?)。取决于你的程序,它可能会导致一些线索。减少能见度(或删除方法)也有时也有所帮助。 – justin 2012-02-11 09:42:10

在我的具体情况下,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" 
} 
+0

这只是UB – paulm 2014-11-13 08:42:38

+1

@paulm,是的,在这个答案中已经用粗体字提到了。 – iammilind 2014-11-14 08:50:39