CppCoreGuidelines C.33 如果类拥有指针成员的所有权,则须定义析构函数
01 September 2022
C.33: If a class has an owning pointer member, define a destructor
理由
在对象析构的时候,必须删除其所拥有的对象。
例子
指针成员代表着一个资源。不建议这样使用T*
,但是在早期代码里,这种用法很常见。考虑到T*
可能占有资源,以下代码就可能有问题了。
template<typename T> class Smart_ptr { T* p; // BAD: vague about ownership of *p // ... public: // ... no user-defined default operations ... }; void use(Smart_ptr<int> p1) { // error: p2.p leaked (if not nullptr and not owned by some other code) auto p2 = p1; }
注意,如果你定义了析构函数,那么你要么定义所有的默认操作,要么删除所有的默认操作:
template<typename T> class Smart_ptr2 { T* p; // BAD: vague about ownership of *p // ... public: // ... no user-defined copy operations ... ~Smart_ptr2() { delete p; } // p is an owner! }; void use(Smart_ptr2<int> p1) { auto p2 = p1; // error: double deletion }
默认的复制操作只会浅浅地将p1.p
复制到p2.p
,从而导致重复释放p1.p
。注意以下代码中的所有权关系:
template<typename T> class Smart_ptr3 { owner<T*> p; // OK: explicit about ownership of *p // ... public: // ... // ... copy and move operations ... ~Smart_ptr3() { delete p; } }; void use(Smart_ptr3<int> p1) { auto p2 = p1; // OK: no double deletion }
注意
通常来说,获得一个析构函数的最简单的方法是用智能指针( std::unique_ptr
)替代原始指针,然后让编译器去隐式的分配合适的析构方法。
注意
为何不要求所有的指针都必须是“智能指针”?因为强求的话,有时候会导致大量的代码变更,而且可能影响 ABI。
强化
- 类中如果有指针成员数据,就要仔细检查下是否有问题
- 类中如果有
owner<T*>
就必须定义其默认操作函数