2014-06-09 84 views
8

here所示如何检测指示器的删除,可以使用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 

它解释说检测到vtable的删除。

但我想知道如何可能,因为我们不覆盖释放的内存?

而且该解决方案是否完全可移植?

感谢

+0

我猜''dynamic_cast '使用[RTTI](http://en.wikipedia.org/wiki/Run-time_type_information)来验证被转换为的类型。 –

+0

我怀疑这是平台依赖的行为。 –

+0

Visual Studio 2013使用此代码抛出“__non_rtti_object”异常。 –

回答

6

首先,试图以任何形式导致不确定的行为,以使用已删除的对象:任何导致你看到可能发生!

观察到的行为的原因很简单,就是一个对象在销毁期间改变类型:从具体类型的对象开始,它通过层次结构中的所有类型进行更改。在每个点上,虚函数都会改变,并且vtable(或类似的)被替换。 dynamic_cast<...>()只检测对象位置处的字节中的这种变化。

如果您想表明此技术无法可靠地工作,您可以将已删除内存的内容设置为随机位模式或最衍生类型对象的位模式:随机位模式可能会导致崩溃,并且可能声称对象仍然是生命。当然,由于它是未定义的行为,任何事情都可能发生。

上的一个有关节本3.8 [basic.life]第5款:

前一个对象的生命周期已经开始,但是对象将占用已分配或寿命后贮存后一个对象已经结束,并且在对象占用的存储器被重新使用或释放​​之前,可以使用任何指向该对象将存在或所处位置的存储位置的指针,但只能以有限的方式使用。正在建造或破坏的物体见12.7。否则,这样的指针指向分配的存储器(3.7.4.2),并且使用指针就好像指针是void*, 类型是明确定义的。如下所述,允许通过这种指针的间接方向,但是结果的左值只能以有限的方式使用。该计划不确定的行为,如果:

  • ...
  • 指针用作dynamic_cast的(5.2.7)的操作。 ...

奇怪的是,在dynamic_cast在最后一颗子弹的例子中不使用dynamic_cast

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