2011-10-22 65 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进行编译,则会引发运行时错误。