【问题标题】:Does the C++ destructor actually delete stuff?C++ 析构函数真的会删除东西吗?
【发布时间】:2012-12-22 07:33:42
【问题描述】:

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

#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() 时会发生什么?有什么情况有用吗?

【问题讨论】:

  • 这并不奇怪,如果你打破规则,你就不会得到你期望的结果。不打破规则,你就不会有这些问题。
  • 它不必崩溃。它可以让电脑偶尔休息一下。
  • C++ 不是 C。不要在有关 C++ 的问题上使用 [c] 标签。
  • 您的问题基本上是“如果这是未定义的行为,为什么它不会使我的计算机爆炸?”请阅读c-faq.com/ansi/experiment.html
  • 可能是因为指针仍然指向相同的内存地址,尽管它已被释放(这并不意味着它被归零)?

标签: c++


【解决方案1】:

手动调用析构函数就像调用一个函数——代码被执行,但内存没有被释放,而不是在内存被释放时调用delete

在删除a 后访问它会导致未定义的行为,并且看起来可以正常工作。

【讨论】:

    【解决方案2】:

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

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

    当我直接调用 ~A() 时会发生什么?

    在你的例子中什么都没有,因为你没有删除那个对象,而是you shouldn't do it

    在什么情况下这样做有用?

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

    【讨论】:

    • “什么都没有”发生是不正确的,析构函数运行。但是没有释放内存
    • @JonathanWakely 好吧,从技术上讲,内存是由析构函数中的delete 释放的。对象的内存没有被释放。
    • 优秀:) 很好的答案。链接完美地解释了它。干杯。
    • @LuchianGrigore,是的,我应该更准确,谢谢
    【解决方案3】:

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

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

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

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

    【讨论】:

      【解决方案4】:

      如您所见,我调用了析构函数 ~A(),因此在我的预期中,程序在尝试第二次访问变量“a”时应该会崩溃(因为它在 2 行前被删除了)。相反.. 程序只是打印出来,没有任何抱怨:

      不足为奇。正如您所注意到的,代码有问题。所以它不会做你期望的事情,而是一些难以预测或理解的事情。如果您想要行为可预测的代码,则必须遵守规则。这就是他们的目的。

      “有人告诉我,在篮球中你不能拿着球跑。我拿了一个篮球试了一下,效果很好。他显然不懂篮球。” ——罗杰·米勒

      【讨论】:

        猜你喜欢
        • 2013-12-21
        • 2011-06-01
        • 2016-11-14
        • 2012-04-06
        • 1970-01-01
        • 2013-07-24
        • 1970-01-01
        • 2011-12-13
        • 2012-11-28
        相关资源
        最近更新 更多