【问题标题】:In what kind of situation, c++ destructor will not be called? [closed]什么情况下不会调用c++的析构函数? [关闭]
【发布时间】:2023-04-04 02:31:01
【问题描述】:

在 c++ 中,我们喜欢在析构函数中做一些事情。但是什么情况下不会调用析构函数呢?

以下情况的示例:

  1. exit()在线程中调用
  2. 未处理的异常并退出
  3. TerminateProcess()(在 Windows 中)
  4. 热/冷重启计算机
  5. 电脑突然断电...

【问题讨论】:

  • 当异常未处理时仍会调用析构函数。试图列举您的计算机可能发生灾难性故障的所有原因(从您的程序的角度来看)是徒劳且无用的信息,您仍应继续使用析构函数并继续假设它们被调用无论如何。
  • @meagar:我相信如果为非处理异常调用析构函数,则它是实现定义的。基本上它归结为:如果进程终止执行,则(显然)不会调用析构函数。我能想到的唯一其他时间是由析构函数引发异常引起的,这几乎从未发生过。哦,还有动态内存。
  • 看来他是在依赖构造函数来释放远程资源。嗯....如果您的进程没有响应,也许您应该让远程资源所有者 ping 您的进程并释放。
  • 大型强子对撞机创造奇点。
  • @TonyTheLion 不可能有洪水前的洪水。

标签: c++ call destructor


【解决方案1】:

这是每个 C++ 程序员都应该知道的一种情况:

#include <stdio.h>

class EmbeddedObject {
   private:
      char *pBytes;
   public:
      EmbeddedObject() {
         pBytes = new char[1000];
      }
     ~EmbeddedObject() {
         printf("EmbeddedObject::~EmbeddedObject()\n");
         delete [] pBytes;
      }
};

class Base {
  public:
    ~Base(){
       printf("Base::~Base()\n");
  }
};

class Derived : public Base {
   private:
      EmbeddedObject emb;
   public:
      ~Derived() {
         printf("Derived::~Derived()\n");
      }
};


int main (int argc, const char * argv[])
{
  Derived *pd = new Derived();
  // later for some good reason, point to it using Base pointer
  Base* pb = pd;
  delete pb; 
}

~Base() 将被调用,但 ~Derived() 不会。这意味着~Derived() 中的代码不会执行。它可能必须做一些重要的事情。此外,EmbeddedObject 的析构函数应该被自动调用,但不是。因此,EmbeddedObject 没有机会释放其动态分配的数据。这会导致内存泄漏。

解决办法,在类Basevirtual中创建析构函数:

class Base {
  public:
    virtual ~Base() {
    }   
};

对上述程序进行这一更改意味着所有析构函数都将在此 oder 中调用:Derived::~Derived()EmbeddedObject::~EmbeddedObject()Base::~Base()

阅读一般的析构函数。与您提到的其他情况相比,这些类型的问题更可能是您关心的问题。例如,在断电的情况下,安全清理的所有赌注通常都失败了!

在 C++ 中,我们可以很好地控制按我们希望它们发生的顺序调用析构函数,这是个好消息。但是,在您编写的程序中,如果您不够小心,您的对象可能会被泄露并且根本不会被删除。

【讨论】:

  • 在这种情况下,这是未定义的行为,但在实践中会起作用。但是,将std::string 放入Derived 中,您也会有实际的内存泄漏。
  • 你能澄清一下:“未定义的行为,但在实践中会起作用”在这种情况下?虚拟或非虚拟析构函数。
  • 非虚拟是未定义的行为,但我想它会在实践中起作用,因为 Derived 有一个微不足道的析构函数并且没有成员
  • 以上代码是在VC++上测试的。 Derived dtor 被 not 调用。对于在 dtor 或对象成员变量中运行代码的类,其 dtor 也不会被调用,这将是一个大问题。
  • 我从未说过会这样。简单地说,在这个示例代码中,没有任何不好的事情发生(除了 UB),因为 Derived 有一个微不足道的析构函数并且没有成员。您的回答是准确的,但我认为如果您在Derived 中添加std::string,这一点会更清楚。
【解决方案2】:

将不会为无限循环范围之外的对象调用析构函数。

【讨论】:

    【解决方案3】:

    如果您使用placement new 创建对象,则不会自动调用该对象的析构函数。

    【讨论】:

    • 用常规新也。新展示位置没有什么新内容。
    • @kbok:换句话说,“动态对象具有手动管理的生命周期。”
    • 这对于抛出异常的罕见析构函数尤其危险。如果包含对象的析构函数抛出异常,许多容器将泄漏对象和内存。
    【解决方案4】:

    Appart 从提到的明显的事情,即退出(),终止信号,电源故障等。

    有一些非常常见的编程错误会阻止调用析构函数。

    1) 创建一个动态对象数组 object* x = new object[n],但使用 delete x 而不是 delete[] x; 释放

    2) 不是在对象上调用 delete(),而是调用 free()。虽然通常会释放内存,但不会调用析构函数。

    3) 假设您有一个对象层次结构,它应该声明 virtual destructors 但由于某种原因没有声明。如果其中一个子类实例在层次结构中被强制转换为不同的类型然后被删除,它可能不会调用所有的析构函数。

    【讨论】:

      【解决方案5】:

      在另一个因抛出异常而被调用的析构函数中抛出异常。

      【讨论】:

      • 那只是调用std::terminate,已经确定不调用析构函数了。
      • @MooingDuck 啊。我看到你在我发布这个答案的同时把它放在评论中。对此感到抱歉。
      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2022-10-15
      • 2010-11-18
      • 1970-01-01
      • 2020-06-20
      • 2014-07-19
      • 2012-10-04
      相关资源
      最近更新 更多