dynamic_cast<>在什么情况下/情况下可能会失败?
In what situations / circumstances a dynamic_cast<> can fail?
在修复庞大代码库中的一个错误时,我观察到一个奇怪的情况,引用的动态类型从原始Derived
类型变为Base
类型!我正在提供解释问题的最小代码:
struct Base {
// some 'virtual' function
protected: // copy constructor
private: // assignment operator
};
struct Derived : Base {
... // There are few more classes between `Base` and `Derived`
... // but for simplicity, I have put direct relation
};
void foo (Base &ref)
{
SomeClass obj;
obj.pVoid = &ref; // pVoid is of void*
// ----> typeid(ref) = Derived
(*funcptr)(obj);
// ----> typeid(ref) = Base !!!
Derived *p = dynamic_cast<Derived*>(&ref); // this fails ... i.e. "p = 0"
}
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()
的道德等价物 - 被调用的函数使用布局
new
在obj.pVoid
指向的地址处构造一个新对象,即类似于new(obj.pVoid) Base()
的对象 - 某些内容正在重写内存,导致在引用的位置留下
Base
对象 - 可能还有更多的原因
就我个人而言,我会把赌注押在第二种情况上,即一个对象被构造到该位置。显然,如果没有看到被调用的函数,就无法判断。
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"
}
相关文章:
- C++ strcpy 函数在少数主要情况下失败
- 在特定情况下失败
- 在儿童的特定情况下,向下渗透MIN二进制堆失败
- 在这种情况下,插入 std::map 可能会失败?
- 为什么我的代码在没有 chroot 函数的情况下工作,但使用 chroot 函数失败?
- 调试断言仅在某些情况下失败?C++
- “overload_cast”在特定情况下失败
- 在这种情况下,SetContextProperty()如何失败
- 解决方案重新生成在 30% 的情况下失败
- 在某些情况下,通配符模式匹配失败
- inotify_add_watch在没有此类文件或目录的情况下失败
- C 标准是否指定在某些情况下,编译应在错误中失败
- 在某些情况下,我的快速排序实现失败
- 在 boost::lockfree:queue 默认构造函数的情况下断言失败
- 为什么在这种情况下c++模板参数推导失败
- 尝试在 QLabel 上绘画失败(无法在没有对象的情况下调用成员函数"虚拟无效 QLabel::p aintEvent(QPaintEvent*)")
- 运行时检查失败 #3 - 变量"result"在未初始化的情况下被使用
- 'new'语句是否可以在不引发异常的情况下失败?
- 为什么程序在没有尝试/捕获的情况下失败
- 复制构造函数在相同的情况下失败或成功