CppCoreGuidelines C.127 有虚函数的类应该也要有虚的或保护的析构函数
09 December 2022
C.127: 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
注意
很多人不遵循本条建议,他们计划只通过共享指针shared_ptr
使用这些类,如
std::shared_ptr<B> p = std::make_shared<D>(args)
。因为共享指针会处理好删除操作,所以不会导致不恰当的使用基类的 delete
而造成的内存泄漏。人们习惯了这个操作,会产生一种不会出错的假象。但是这条指南很重要。如果有人使用make_unique
分配内存怎么办?这样会有不安全的行为。除非 B
的作者确保别人不会误用 B
,比如将所有的构造函数设置为 private
,并提供一个工厂函数,确保通过make_shared
分配资源。
强化
- 类如果有虚函数,则应该有一个析构函数,要么是公开的虚函数,要么是保护的非虚函数。
- 标记这类情况:删除一个类对象的时候用了
delete
而这个类有虚函数,但是没有虚析构函数。