2013-02-28 47 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

相關問題