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

时间:2013-07-15 00:43:12

标签: c++ destructor

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

刚开始在C ++中学习这一点并需要澄清。

6 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分: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,而且您再也不必重复获取和释放逻辑。

答案 4 :(得分:0)

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

您可以使用析构函数实现RAII-style功能。

利用此功能的类型示例:

std::fstream关闭已打开的文件

std::lock_guard解锁互斥锁

如果计数器为0,

std::shared_ptr会递减引用计数器或释放内存。

答案 5 :(得分:0)

您需要定义一个析构函数的实例:

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