C++特殊成员函数生成规则
在C++中,特殊成员函数(special member functions)由编译器隐式声明并可能生成,包括默认构造函数、析构函数、拷贝/移动构造与赋值,以及新引入的默认比较运算符。这些函数的生成规则取决于用户声明、成员类型和基类。规则设计鼓励零规则(Rule of Zero):依赖编译器默认行为管理资源,避免自定义。

1. 特殊成员函数种类
C++20中共8种:
- 默认构造函数
T() noexcept; - 析构函数
~T(); - 拷贝构造函数
T(const T&); - 拷贝赋值运算符
T& operator=(const T&); - 移动构造函数
T(T&&) noexcept; - 移动赋值运算符
T& operator=(T&&) noexcept; - 默认等于运算符(C++20)
bool operator==(const T&) const; - 三路比较运算符(C++20)
std::strong_ordering operator<=>(const T&) const noexcept;
2. 生成规则详解(C++20)
2.1 默认构造函数
- 生成:无用户声明任何构造函数时生成。
- 行为:成员默认初始化(内置类型值初始化为零,类类型调用其默认ctor)。
- 抑制:用户声明任何ctor,或有不可默认构造成员/基类(const/引用无初始化器)。
- 控制:
= default;生成,= delete;禁止。
2.2 析构函数
- 生成:无用户声明时总是生成(trivial若可能)。
- 行为:逆序销毁成员/基类。
- noexcept:默认
noexcept(true)。 - 抑制:用户声明(含
= default)。 - 最佳:基类用虚析构
= default;。
2.3 拷贝构造函数
- 生成:无用户声明拷贝ctor、移动ctor或移动assign时。
- 行为:成员/基类逐拷贝。
- 抑制(C++11起):用户声明移动ctor/assign,或不可拷贝成员/基类。
- 控制:
= default/delete;。
2.4 拷贝赋值运算符
- 生成:无用户声明拷贝assign、移动ctor或移动assign时。
- 行为:成员/基类逐赋值(self-assign安全)。
- 抑制:用户声明移动ctor/assign,或不可赋值成员/基类。
- 控制:
= default/delete;。
2.5 移动构造函数
- 生成:无用户声明拷贝ctor、拷贝assign、移动ctor、移动assign或析构时。
- 行为:成员/基类逐移动(内置类型位拷贝)。
- 抑制:用户声明拷贝ctor/assign、移动assign、析构,或不可移动成员/基类。
- noexcept:若所有移动操作noexcept,则noexcept。
- 控制:
= default/delete;。
2.6 移动赋值运算符
- 生成:同移动ctor。
- 行为:释放旧资源,逐移动赋值。
- 抑制:同移动ctor。
- noexcept:同上。
- 控制:
= default/delete;。
2.7 默认等于运算符(C++20)
- 生成:无用户声明
==或<=>时。 - 行为:成员/基类逐
==(等价关系)。 - 签名:
bool operator==(const T&) const = default; - 抑制:不可==成员/基类(无公开==),或union有const/引用无brace-init成员。
- 控制:
= default;(若可能),= delete;。
2.8 三路比较运算符(C++20)
- 生成:无用户声明
<=>、==、operator<、operator>等6个比较时。 - 行为:成员/基类逐
<=>,返回strong_ordering(若异质则partial_ordering等)。 - 签名:
strong_ordering operator<=>(const T&) const noexcept = default; - 抑制:不可
<=>成员/基类,或有异质比较需求。 - 隐式生成:
<=>隐式生成==、!=、<、>、<=、>=。 - 控制:
= default;(指定strong_ordering/partial_ordering/weak_ordering),= delete;。
3. 生成规则总结表
| 特殊函数 | 默认生成条件 | 主要抑制条件 |
|---|---|---|
| 默认ctor | 无任何ctor声明 | 任何ctor声明,不可默认构造成员 |
| 析构 | 无声明 | 用户声明 |
| 拷贝ctor | 无拷贝ctor/移动ctor/移动assign | 移动ctor/assign声明,不可拷贝成员 |
| 拷贝assign | 无拷贝assign/移动ctor/移动assign | 移动ctor/assign声明,不可赋值成员 |
| 移动ctor | 无拷贝ctor/assign/移动ctor/assign/析构 | 拷贝/析构声明,不可移动成员 |
| 移动assign | 同移动ctor | 同移动ctor |
| == (C++20) | 无==/<=>声明 | 不可==成员/基类 |
| <=> (C++20) | 无比较运算符声明 | 不可<=>成员/基类 |
4. C++20变化与最佳实践
- 比较运算符:自动化成员比较,简化
==/<等。= default;<=>隐式所有6运算符。 - Rule of Zero:优先标准容器(如
unique_ptr),零自定义特殊函数。 - Rule of Five:自定义资源管理时定义析构+4拷贝/移动。
- noexcept:移动操作标
noexcept提升容器性能(vector resize等)。 - 删除传播:不可拷贝成员使类不可拷贝。
- 简洁:避免边界case,用
= default/delete明确意图。复杂继承/资源用组合。
5. 示例
#include <iostream>
#include <compare> // std::strong_ordering
struct Point {
int x, y;
auto operator<=>(const Point&) const = default; // 生成所有比较
};
struct Movable {
int* ptr;
Movable() = default;
~Movable() { delete ptr; }
Movable(const Movable&) : ptr(new int(*other.ptr)) {} // 自定义拷贝
Movable& operator=(const Movable&) { /* impl */ return *this; }
// 移动隐式删除,因自定义析构/拷贝
Movable(Movable&&) = default; // 显式启用
};
int main() {
Point p1{1,2}, p2{1,2};
std::cout << (p1 == p2) << '\n'; // true,隐式==
Movable m; // 默认ctor
return 0;
}6. 常见陷阱
- 移动被抑制:自定义析构/拷贝→无隐式移动,标
= default;。 - 比较union:const/引用成员需小心。
- 异质比较:
<=>需指定partial_ordering。 - 虚函数:有虚析构→比较非const。
此规则确保零开销抽象,遵循KISS:简单胜于复杂。




