2011-10-22 70 views
1

我研究過每當對象超出範圍或者使用delete運算符取消分配的內存時,都會調用DestructorC++中的析構函數調用

#include <iostream> 

using namespace std; 

class point 
{ 
    private: 
     int x_coord; 
     int y_coord; 

    public: 
     point() 
     { 
     x_coord = 0; 
     y_coord = 0; 
     } 

     point(int x, int y) 
     { 
     x_coord = (x > 79 ? 79 : (x < 0 ? 0 : x)); 
     y_coord = (y > 79 ? 79 : (y < 0 ? 0 : y)); 
     } 

     ~point() 
     { 
     cout << "Destructor invoked\n"; 
     } 

     int getx(void) 
     { 
     return x_coord; 
     } 

     int gety(void) 
     { 
     return y_coord; 
     } 
}; 

int main() 
{ 
    point p1; 
    point p2(20, 80); 

    point *p3 = new point; 

    cout << "p1.x = " << p1.getx() << ": p1.y = " << p1.gety()<< "\n"; 
    cout << "p2.x = " << p2.getx() << ": p2.y = " << p2.gety()<< "\n"; 
    cout << "p3->x = " << p3->getx() << ": p3->y = " << p3->gety()<< "\n"; 

    point * p4 = &p1; 
    delete p4; 
    delete p3; 

    return 0; 

} 
  1. 分配給P1的內存使用delete p4取消分配。因此調用析構函數
  2. delete p3調用下一個析構函數。
  3. p2超出範圍並調用下一個析構函數。

我期望的析構函數只能被調用3次。但我看到調用4次析構函數。這是什麼原因?關於我對破壞者的理解,是否存在一些錯誤

+0

我不認爲'刪除p4'是正確的。 – cnicutar

+2

你不應該'''''p1'因爲它被分配到堆棧上。 – ObscureRobot

+0

如果您刪除了調用這些方法的'main()'中的析構函數,字段和代碼的所有方法,則可以大大縮短您的示例。他們與你的問題無關。 – ObscureRobot

回答

4

代碼中存在錯誤。您不能delete p1p4指向p1),因爲它不是用new創建的。因此,該程序正在調用未定義的行爲。

在這種特殊情況下會發生什麼情況是p1的析構函數會被調用兩次:第一次是delete,第二次是p1超出範圍。它也可以是其他任何東西(其他可能的結果是崩潰)。

4

您將會破壞p1兩次,一次是當p1超出範圍,而且當你調用delete p4,這僅僅是一個指針p1,而不是一個單獨的對象。銷燬一個對象兩次是未定義的行爲,順便說一句(正如刪除一個堆棧對象(見評論))。

+0

它不是UB,因爲一個對象被銷燬兩次,但它是一個UB,因爲沒有被'new'返回的地址被傳遞給'delete'。 'p1'是堆棧中的對象,而不是freestore。 –

+0

@Als:好點! –

1

p1被分配到堆棧上,所以即使您在p4上調用delete,也會在現在未分配的p1上調用delete。

請注意,釋放內存不會(必然)將其歸零。所以可以再次調用析構函數並打印消息。或者它可能會炸燬。這就是爲什麼確保在上次使用前不要釋放內存的原因。

0

您通過指針p4銷燬p1是無效的,如果您正在使用調試CRT進行編譯,則會引發運行時錯誤。