2013-02-28 48 views
-1

I所述使用MS Visual Studio 2010中调用同一对象多次的析构函数,如在标准

我制成实施双链表的结果是不相同的。

我想知道为什么在调用方法Clean后,在调用对象的析构函数后,在引用该对象之后,不会引发任何错误。

下面是我的一些双链表的方法(相对于我的问题):

/*DoubleLinkedList.cpp */ 
     DoubleLinkedList::~DoubleLinkedList(void) 
     { 
     cout << "Destructor invoked" << endl; 
     // as for data nodes memory is allocated in heap we have to release it: 
     const Node* const_iterator = m_head.m_next; 
     while (const_iterator != &m_tail) 
     { 
      const_iterator = const_iterator->m_next; 
      delete const_iterator->m_prev; 
     } 
    } 

void DoubleLinkedList::Clean(void) 
{ 
    cout << "Clean invoked" << endl; 

    this->~DoubleLinkedList(); /* According to C++ 11 standart: Once a destructor is invoked for an object, the object no longer exists*/ 
} 

/* main.cpp */ 
    int main(int argc, char* argv[]) 
    { 
     DoubleLinkedList list; 
     Circle c1, c2(MyPoint(1,1),50), c3(MyPoint(2,2),30); 
     list.Front(&c1); 
     list.Front(&c2); 
     list.Front(&c3); 
     list.Show(); 
     list.Sort(); 
     list.Show(); 
     list.Clean(); 
     list.Show(); /* Recall how Clean method is implemented. As list no longer exist, run-time error is expected here, but flow of executon continues and Show, Push_back preforms fine*/ 
     list.Push_back(&c1); 
     list.Push_back(&c2); 
     list.Push_back(&c3); 

问题: * 在C语言中的11非标准++声明析构函数被调用后 - 对象中没有更长的存在 *,为什么我仍然能够在调用析构函数后使用该对象?

+2

引用一个不再存在的对象是* undefined behavior *。这意味着你的程序可能会崩溃,或者它可能不会。 C/C++不提供安全网络,并且不需要告诉你是否犯了错误。 – DevSolar 2013-02-28 08:51:32

+2

另请参阅:http://stackoverflow.com/a/6445794/78845 – Johnsyweb 2013-02-28 08:54:51

+0

您误解了它。我认为真正的意思是*当对象不再存在时,它的析构函数应该被称为*。 C++编译器保证在退出范围时自动调用每个对象的析构函数。 – neuront 2013-02-28 08:55:46

回答

3

这里要考虑的重要一点是对象的生存期。对象的生命周期必须在分配该对象的存储的时间内存在。在分配存储的时间内,一个接一个存储多个对象。

通常,当一个对象被销毁(通过超出范围或调用delete)时,对象的生存期结束,然后释放其内存。但是,当您明确调用析构函数时,您所做的只是终止对象的生命周期。该标准没有定义“不存在”的对象,但它确实有其终生结局的概念。

T类型的对象的生存期结束时:

  • 如果T是具有一个非平凡的析构函数(12.4),析构函数呼叫开始一个类型,或
  • 存储物体占据的位置被重用或释放。

现在,在状态后的对象生命周期已经结束,其存储已释放之前,有唯一可以做的非常具体的事情。该标准定义了在这个状态下可以完成的事情,包括指针和glvalues。在你的情况,list是glvalue,所以我们就来看看规则为:

[...]一个对象的生命周期结束之后和存储之前该对象 占据被重用或释放,任何引用原始对象的glvalue都可以使用,但只能以有限的方式使用。 [...]该方案具有未定义的行为,如果:

  • 左值到右值转换(4.1)被施加到这样的glvalue,
  • 的glvalue用于访问非静态数据成员或者调用该对象的非静态成员函数,或者将glvalue隐式转换(4)。10)到一个参照本发明的基类型,或
  • 的glvalue用作的static_cast(5.2.9除了当转换为最终的操作数),以CV char&或CV unsigned char&,或
  • 的glvalue被用作dynamic_cast(5.2.7)的操作数或作为typeid的操作数。

第二个列表项在这里适用。您有未定义的行为,因为您在对象生存期结束后访问非静态成员函数。

+0

如果对象不再存在,应该删除与它关联的所有支持信息(例如,我的意思是虚拟表),如果是这样,为什么仍然可以调用该对象的方法或者invokage是未定义的行为? – 2013-02-28 10:10:31

+1

@spin_eight它是未定义的行为。该标准没有提到虚拟表格等。任何事情都可能发生。 – 2013-02-28 10:31:47

2

使用对象在它被销毁之后(即析构函数被调用)是UB。 UB意味着未定义的行为。所以......

+0

...但是,正如上面的代码所展示的,销毁对象并不是调用析构函数的唯一方法! – Johnsyweb 2013-02-28 09:01:18

+1

@Johnsyweb和什么?如果调用析构函数 - 对象的使用是UB。 – ForEveR 2013-02-28 09:24:59

相关问题