The Rule of The Big Six指C++11起社区对六个关键特殊成员函数的统称:默认构造函数、析构函数、拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符;手动定义其一通常需显式定义其余,以避免资源管理错误。

什么是 The Rule of The Big Six
“The Rule of The Big Six”不是 C++ 标准里的正式术语,而是社区对 C++11 起(尤其 C++20 强化后)六个关键特殊成员函数的统称:它们共同决定一个类如何管理资源。如果你手动定义了其中任何一个,大概率需要显式定义其余几个,否则容易引发浅拷贝、重复释放、移动后访问野指针等问题。
六个函数分别是什么
它们是:
-
default constructor(默认构造函数) -
destructor(析构函数) -
copy constructor(拷贝构造函数) -
copy assignment operator(拷贝赋值运算符) -
move constructor(移动构造函数) -
move assignment operator(移动赋值运算符)
注意:default constructor 有时被替换成 defaulted destructor 或省略——真正核心是后五个。C++20 中,= default 和 = delete 的语义更清晰,编译器对移动操作的隐式生成规则也更严格(比如:只要用户声明了任何拷贝/移动操作,编译器就不再自动生成移动构造/赋值)。
为什么不能只写析构函数就完事
常见错误场景:你写了 ~MyClass() 来 delete 原生指针,但没写移动或拷贝函数:
立即学习“C++免费学习笔记(深入)”;
class BadExample {
int* data;
public:
BadExample() : data(new int[100]) {}
~BadExample() { delete[] data; } // ✅ 析构写了
// ❌ 没写 copy/move —— 编译器会合成默认的(逐成员复制)
};后果:
- 拷贝时
data被浅复制 → 两个对象指向同一块内存 → 双重delete[] - C++11 后,若没声明移动函数,编译器可能不生成移动版本 → 本可移动的场景被迫拷贝(性能损失)
- C++20 中,一旦你声明了
~BadExample(),编译器就不再隐式声明移动构造/赋值(即它们变成deleted),此时std::vector的push_back可能编译失败
实际怎么写才安全
优先用 RAII 容器(如 std::vector、std::unique_ptr),避免裸指针。如果必须管理原生资源,按需显式定义:
- 只读/不可拷贝类型 → 删除拷贝,保留移动:
BadExample(const BadExample&) = delete;、BadExample& operator=(const BadExample&) = delete; - 需要值语义(如
std::string)→ 实现深拷贝 + 移动窃取(std::swap或nullptr交换) - 想让编译器生成默认行为 → 显式写
= default(尤其移动函数在 C++20 中不会自动合成)
示例(安全且符合 C++20):
class GoodExample {
std::unique_ptr data;
public:
GoodExample() : data(std::make_unique(100)) {}
~GoodExample() = default; // ✅ unique_ptr 自动清理
// ✅ 默认拷贝/移动都可用(unique_ptr 禁止拷贝、允许移动)
GoodExample(const GoodExample&) = delete;
GoodExample& operator=(const GoodExample&) = delete;
GoodExample(GoodExample&&) = default;
GoodExample& operator=(GoodExample&&) = default;
};
真正麻烦的永远不是“要不要写六个”,而是“你是否意识到某个函数正被隐式删除,而你的容器或算法正依赖它”。C++20 把这种隐式行为收得更紧,反而更容易暴露问题——这不是限制,是提示你该检查资源契约了。











