C ++析构函数实际上是否删除了东西?

时间:2013-01-08 12:38:50

标签: c++

我知道delete运算符以及它如何自动调用类的析构函数。但是,我最近看到有人直接调用了类的析构函数,这对我来说似乎很奇怪。所以我写了一个简短的程序,给出了一个非常不期望的结果:

#include <stdio.h>

class A
{
public:
  A()  {a = new int; *a=42; b=33;}
  ~A() {delete a;}

  int* a;
  int  b;
};

int main(int argc, const char ** argv)
{
  A* myA = new A();
  printf("a:%d  b:%d\n", *(myA->a), myA->b);
  myA->~A();
  printf("b:%d\n", myA->b);
  printf("a:%d\n", *(myA->a));
}

所以如你所见,我正在调用析构函数~A(),所以我希望程序在第二次尝试访问变量'a'时会崩溃(因为它在2行之前被删除了)。相反......程序只是打印出来而没有任何抱怨:

a:42  b:33
b:33
a:42

......为什么?当我直接调用~A()时会发生什么?有什么情况可以这么做吗?

4 个答案:

答案 0 :(得分:9)

手动调用析构函数就像调用函数一样 - 执行代码,但释放内存时不释放内存,而不释放内存。

删除delete后会导致未定义的行为,并且似乎可以正常工作。

答案 1 :(得分:3)

直接调用~A()时,会执行析构函数的代码。这不会阻止析构函数被通常再次调用,就像C ++一样。例如:

void func()
{
   A a;
   a.~A();  // calls destructor
   // Destructor runs again here as it always would.
}

在您的示例中,将释放int的内存。这只是意味着运行时会记下你的程序不再使用内存......但这并不一定意味着内存会立即被擦除或用于其他内容。因此,当您稍后访问int的内存时,它仍然包含相同的值。但是,有一些其他线程有可能重用这个内存而其他东西可能会覆盖它,但这恰好不会发生在你的程序中。

直接调用~A()很有用的情况是,您希望在某些情况下处理自己的内存分配。例如,您可能拥有自己的字符串类并一次保留大量内存。您可以手动调用构造函数和析构函数来设置此池中的内存区域,以便正确初始化字符串。您可以这样做而无需进行任何新分配 - 只需重用池即可。但是......我会说这是专家级编程,你需要知道你正在做什么,并且这样做是为了获得有价值的性能提升。

答案 2 :(得分:3)

  

当尝试第二次访问变量'a'时程序应该崩溃

访问已删除的变量是一种未定义的行为。这意味着任何事情都可能发生,包括程序崩溃。

  

当我直接打电话给A()时会发生什么?

在您的示例中没有,因为您不删除该对象,而是you shouldn't do it

  

有什么情况可以这么做吗?

是的,析构函数should be explicitly be called for placement new,这是应该调用析构函数的唯一情况。

答案 3 :(得分:2)

  

所以如你所见,我正在调用析构函数~A(),所以我希望程序在第二次尝试访问变量'a'时会崩溃(因为它在2行之前被删除了)。相反......程序只是打印出来而没有任何抱怨:

不足为奇。正如您所注意到的,代码是错误的。因此,它不会按照您的预期进行,但难以预测或理解。如果您希望代码具有可预测的行为,则必须遵循规则。这就是他们的目的。

  

“有人告诉我,在篮球比赛中,你无法控球并且跑动。我得到了一个篮球并尝试了它并且效果很好。他显然不懂篮球。” - 罗杰米勒