C++自定义类实现时是否需要遵循Rule of Five(五法则)?
C++特殊成员函数定义最佳实践
问题背景
C++语言规则中对特殊成员函数的隐式生成有明确约束:
如果类中存在用户自定义(或通过
= default、= delete声明)的析构函数、拷贝构造函数、拷贝赋值运算符,会阻止编译器隐式定义移动构造函数与移动赋值运算符,因此任何需要支持移动语义的类,都必须声明全部五个特殊成员函数。
提问者给出的测试代码如下:
#include <string> #include <iostream> class Data { private: std::string m_name; public: Data() { m_name = "stackman"; } ~Data() = default; Data(const Data&) = delete; Data& operator=(const Data&) = delete; Data(Data&&) = delete; Data& operator=(Data&&) = delete; std::string get_name() { return m_name; } }; int main() { Data person; std::cout << person.get_name() << std::endl; }
提问者发现不同资料存在矛盾描述:有说法称如果析构函数设置为=default,且不需要其他构造、赋值函数,就无需对其进行delete或显式定义,需要明确该场景下的标准最佳实践。
规则说明与实践方案
首先要澄清一个常见误区:用=default声明的析构函数属于用户声明的析构函数,和手写实现的析构函数完全等价,一样会触发编译器隐式移动操作的抑制逻辑,不存在“写=default就不影响其他特殊成员函数生成”的特殊规则。
针对不同需求场景,对应最佳实践如下:
- 场景1:类仅需要在固定作用域内创建使用,禁止拷贝、移动
给出的示例代码可以正常运行,但属于冗余写法。示例中类成员只有std::string,编译器隐式生成的析构函数完全可以正确完成资源释放,不需要手动写~Data() = default;。同时,只要显式delete拷贝构造函数和拷贝赋值运算符,编译器就不会生成默认拷贝操作,也不会隐式生成移动操作,不需要额外手动delete移动构造和移动赋值。
该场景下最简正确实现的特殊成员函数部分只需要保留:Data() { m_name = "stackman"; } Data(const Data&) = delete; Data& operator=(const Data&) = delete; - 场景2:类需要支持移动语义
只要显式声明了析构、拷贝构造、拷贝赋值运算符中的任意一个,就必须显式声明移动构造和移动赋值运算符,要么用=default让编译器生成默认实现,要么编写自定义逻辑,严格遵循五法则要求,避免移动语义被意外抑制。 - 场景3:类不需要自定义资源释放逻辑,所有成员都可以用编译器默认逻辑处理
不需要手动声明任何特殊成员函数,编译器会按规则隐式生成默认构造、析构、拷贝、移动全套操作。不要额外添加=default声明的析构函数,避免画蛇添足导致移动语义被意外抑制。
内容的提问来源于stack exchange,提问作者lvalue
相关产品推荐
相关产品推荐

