0

什么时候类必须在 C++ 类中定义析构函数?为什么?

刚开始在 C++ 中学习这一点,需要对其进行澄清。

4

6 回答 6

5

如果您的类需要进行特殊清理,例如释放动态分配的内存,您只需要定义一个析构函数。

于 2013-07-15T00:45:03.180 回答
3

当您动态分配内存时,您需要定义一个析构函数。一个好的经验法则是,如果你在任何构造函数中使用 new,你可能需要一个析构函数。任何不是自动存储或静态存储的东西都被认为是动态分配的

任何属于清理类别的东西都适合放入析构函数,例如关闭网络连接

于 2013-07-15T00:47:59.110 回答
1

如果析构函数的默认行为不是你想要的,你只需要定义一个析构函数。

当一个对象被销毁时,无论你是否定义了自定义析构函数,析构函数都会做这些事情:

  • 调用每个数据成员的析构函数。
  • 调用每个基的析构函数。

这实际上处理了您可能想要做的大多数事情。在构造函数中分配内存时,通常定义自定义析构函数:

struct A {
    B *b_ptr;

    A() : b_ptr(new B) { }
    ~A() { delete b_ptr; }
};

但是当您使用标准容器和智能指针时,需要自定义析构函数的情况相对较少。例如,如果您有这样的课程

struct A {
    std::unique_ptr<B> b_ptr;

    A() : b_ptr(new B) { }
};

无需定义自己的析构函数,因为 std::unique_ptr 将释放分配的内存。同样,这里不需要定义析构函数

struct B {
    ifstream input_stream;

    B(const std::string &path) : input_stream(path) { }
};

因为input_stream当 input_stream 成员被销毁时将自动关闭。

有时,在某些情况下,您需要做一些特别的事情。您需要一个特殊的调用来获取或释放资源。在这种情况下,您需要一个析构函数:

struct C {
    ResourceHandle resource_handle;
    C() : resource_handle(resouce_manager.acquireResource()) { }
    ~C() { resource_manager.releaseResource(resource_handle); }
};

但是尽可能地,您希望将这种行为本地化,以便它不必在许多类中重复。例如,您可能希望像这样创建类:

struct ResourceHolder {
    ResourceHandle resource_handle;
    ResourceHolder() : resource_handle(acquireResource()) { }
    ~ResourceHolder() { releaseResource(resource_handle); }
};

现在,您只需在需要这些资源之一的每个类中使用 ResourceHolder,您就不必再次重复获取和释放逻辑。

于 2013-07-15T01:09:16.563 回答
1

可能还有其他原因,但我想到的第一个原因是您的某些类属性可能需要明确释放。

如果您的类仅具有两个 int 属性,那么当您调用delete myObject. 但如果它包含任何动态分配的属性,这些属性将不会与您的对象一起被释放,因此您需要在析构函数中明确删除它们。

于 2013-07-15T00:49:04.853 回答
0

析构函数不仅用于释放例如在构造函数中分配的内存。

您可以通过使用析构函数来实现RAII 风格的功能。

利用这一点的类型示例:

std::fstream关闭打开的文件

std::lock_guard解锁互斥锁

std::shared_ptr如果计数器为 0,则递减引用计数器或释放内存。

于 2013-07-15T01:12:05.387 回答
0

有 2 个实例需要定义析构函数:

  1. 您正在类中的某处分配资源,还要考虑复制构造函数和赋值运算符,即使是为了防止它们被使用,您也可能需要定义它们。
  2. 该类将派生自。在这种情况下,析构函数必须是虚拟的。原因是如果派生类将使用引用或指向包含派生类实例的父类的指针来破坏,则不会调用派生类的析构函数。
于 2013-07-15T01:57:56.983 回答