什么时候类必须在 C++ 类中定义析构函数?为什么?
刚开始在 C++ 中学习这一点,需要对其进行澄清。
如果您的类需要进行特殊清理,例如释放动态分配的内存,您只需要定义一个析构函数。
当您动态分配内存时,您需要定义一个析构函数。一个好的经验法则是,如果你在任何构造函数中使用 new,你可能需要一个析构函数。任何不是自动存储或静态存储的东西都被认为是动态分配的
任何属于清理类别的东西都适合放入析构函数,例如关闭网络连接
如果析构函数的默认行为不是你想要的,你只需要定义一个析构函数。
当一个对象被销毁时,无论你是否定义了自定义析构函数,析构函数都会做这些事情:
这实际上处理了您可能想要做的大多数事情。在构造函数中分配内存时,通常定义自定义析构函数:
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,您就不必再次重复获取和释放逻辑。
可能还有其他原因,但我想到的第一个原因是您的某些类属性可能需要明确释放。
如果您的类仅具有两个 int 属性,那么当您调用delete myObject
. 但如果它包含任何动态分配的属性,这些属性将不会与您的对象一起被释放,因此您需要在析构函数中明确删除它们。
析构函数不仅用于释放例如在构造函数中分配的内存。
您可以通过使用析构函数来实现RAII 风格的功能。
利用这一点的类型示例:
std::fstream
关闭打开的文件
std::lock_guard
解锁互斥锁
std::shared_ptr
如果计数器为 0,则递减引用计数器或释放内存。
有 2 个实例需要定义析构函数: