特殊成员函数的定义与分类

特殊成员函数指 C++ 编译器会自动生成的成员函数,不同标准版本涵盖范围不同:

  • C++98:包含 4 种:默认构造函数、析构函数、复制构造函数、复制赋值运算符
  • C++11 及以上:新增 2 种:移动构造函数、移动赋值运算符

编译器自动生成的特殊成员函数,访问层级为public、inline、非虚(除非基类析构函数为虚,派生类析构函数才会为虚)

大三律(Rule of Three)

若声明了复制构造函数、复制赋值运算符、析构函数中的任意一个,就需要同时声明这三个。

需要改写复制操作,通常意味着类涉及裸资源管理(堆内存、文件句柄等):

  1. 一种复制操作中做的资源管理,大概率也需要在另一种复制操作中执行;
  2. 析构函数需参与资源管理(通常是释放资源)。

推论:若用户声明了析构函数,说明类需手动管理裸资源,而编译器默认的 “逐成员复制” 仅拷贝资源标识(如指针地址),而非资源本身,会导致内存泄漏、重复释放等资源管理混乱问题。

C++11 的补充规则

  1. 析构函数影响:只要用户声明了析构函数,编译器不会生成移动操作(移动构造 / 移动赋值);

  2. 复制操作的废弃行为:在已有用户声明的复制操作或析构函数的情况下,编译器仍自动生成复制操作的行为已被废弃;

  3. 移动操作的生成条件(三者需同时满足):

    • 类未声明任何复制操作(复制构造 / 复制赋值);
    • 类未声明任何移动操作(移动构造 / 移动赋值);
    • 类未声明任何析构函数。

C++11 中各类特殊成员函数的生成规则

函数类型 生成规则 运行期行为
默认构造函数 仅当类无用户声明的构造函数时生成(与 C++98 一致) -
析构函数 与 C++98 基本一致,仅默认带noexcept;基类析构为虚则派生类析构为虚 -
复制构造函数 1. 无用户声明的复制构造函数时生成;

2. 声明了移动操作则被删除;

3. 有析构 / 复制赋值时,自动生成行为已废弃
按成员复制非静态数据成员(与 C++98 一致)
复制赋值运算符 1. 无用户声明的复制赋值运算符时生成;

2. 声明了移动操作则被删除;

3. 有析构 / 复制构造时,自动生成行为已废弃
按成员赋值非静态数据成员(与 C++98 一致)
移动构造 / 移动赋值运算符 仅当类无用户声明的复制操作、移动操作、析构函数时生成 按成员移动非静态数据成员

成员函数模板不会抑制特殊成员函数的生成(无论是否定义,编译器仍会按规则生成特殊成员函数)。

总结

  1. 特殊成员函数包含默认构造、析构、复制操作(构造 / 赋值)、移动操作(构造 / 赋值),C++11 比 C++98 多移动操作;
  2. 移动操作仅在类无用户声明的复制操作、移动操作、析构函数时才会被自动生成;
  3. 复制构造 / 赋值仅在无对应用户声明时生成,声明移动操作则会删除复制操作;有显式析构函数时,自动生成复制操作的行为已废弃;
  4. 成员函数模板不影响特殊成员函数的自动生成。