如何使用动态强制转换检测指针的删除

How is the deletion of a pointer detected using dynamic cast

本文关键字:检测 指针 删除 转换 何使用 动态      更新时间:2023-10-16

如图所示,可以使用dynamic_cast来检测已删除的指针:

#include <iostream>
using namespace std;
class A
{
public:
   A() {}
   virtual ~A() {}
};
class B : public A
{
public:
   B() {}
};
int main()
{
   B* pB =  new B;
   cout << "dynamic_cast<B*>( pB) ";
   cout << ( dynamic_cast<B*>(pB) ? "worked" : "failed") << endl;  
   cout << "dynamic_cast<B*>( (A*)pB) ";
   cout << ( dynamic_cast<B*>( (A*)pB) ? "worked" : "failed") << endl;  
   delete pB; 
   cout << "dynamic_cast<B*>( pB) ";
   cout << ( dynamic_cast<B*>(pB) ? "worked" : "failed") << endl;  
   cout << "dynamic_cast<B*>( (A*)pB) ";
   cout << ( dynamic_cast<B*>( (A*)pB) ? "worked" : "failed") << endl;  
}
输出:

dynamic_cast<B*>( pB) worked
dynamic_cast<B*>( (A*)pB) worked
dynamic_cast<B*>( pB) worked
dynamic_cast<B*>( (A*)pB) failed

说明检测到虚函数表的删除。

但我想知道这是怎么可能的,因为我们不覆盖释放的内存?

这个解决方案是完全可移植的吗?

谢谢

首先,尝试以任何形式使用已删除的对象都会导致未定义的行为:您看到的任何结果都可能发生!

观察到的行为的原因很简单,对象在销毁期间改变了类型:从一个具体类型的对象,它通过层次结构中的所有类型改变。在每个点上,虚函数都会发生变化,虚函数表(或类似的表)也会被替换。dynamic_cast<...>()只是检测对象所在位置存储的字节的变化。

如果你想表明这种技术不可靠地工作,你可以把删除的内存的内容设置为一个随机的位模式或最派生类型的对象的位模式:一个随机的位模式可能会导致崩溃,memcpy()可能会声称对象仍然存在。当然,因为它是未定义的行为,所以任何事情都可能发生。

这是3.8的一个相关章节[basic]。生活]第5段:

在对象的生命周期开始之前,但在对象将要占用的存储空间被分配之后,或者在对象的生命周期结束之后,在对象所占用的存储空间被重用或释放之前,任何指向对象将要或曾经所在的存储位置的指针都可以被使用,但只能以有限的方式使用。对于正在构建或销毁的对象,请参见12.7。否则,这样的指针指的是已分配的存储(3.7.4.2),并且将该指针当作void*类型的指针使用,是定义良好的。通过这样的指针进行间接操作是允许的,但是产生的左值只能以有限的方式使用,如下所述。如果:

程序有未定义的行为
  • 指针被用作dynamic_cast(5.2.7)的操作数. ...

奇怪的是,dynamic_cast的最后一个项目的例子并没有使用dynamic_cast

当然,对象也可能被释放,在这种情况下,上面的保证甚至不适用。