CppCoreGuidelines C.127 一个有虚函数的类应该也要有一个虚的或保护的析构函数
09 December 2022
“A class with a virtual function should have a virtual or protected destructor”
理由
一个类如果有虚函数,经常是通过其基类类型的指针间接访问使用。最后用户必须调用 delete 删除其基类类型的指针。并且,通常会通过基类的智能指针使用。因此,析构函数应该是公开的虚函数。
不常见的情况是,如果不允许通过基类的指针删除对象,可以将析构函数设置为保护的非虚函数。see C.35
坏例子
struct B { virtual int f() = 0; // ... no user-written destructor, defaults to public non-virtual ... }; // bad: derived from a class without a virtual destructor struct D : B { string s {"default"}; // ... }; void use() { unique_ptr<B> p = make_unique<D>(); // ... } // undefined behavior, might call B::~B only and leak the string
注意
很多人计划只通过 sharedptr 使用,如 std::shared_ptr<B> p =
std::make_shared<D>(args);
,因此不遵循这条指南建议。因为共享指针会处理好删除操作,所以不会导致因为不恰当的使用基类的 delete 造成内存泄漏。人们习惯这个操作,会导致一种不会出错的假象。但是这条指南很重要。如果有人使用 make_unique
分配内存怎么办?这样会有不安全的行为。除非 B 的作者确保不会误用 B,比如将所有的构造函数设置为 private,并提供一个工厂函数,确保通过 make_shared
分配资源。
强化
- 一个类如果有虚函数,则应该有一个析构函数,要么是公开的虚函数,要么是保护的非虚函数。
- 标记删除一个有虚函数,但是没有虚析构函数的类的对象的操作