编程C++ 开发者

描述 C++11 中的三条规则和五条规则(Rule of Three / Rule of Five)及其在类设计中的重要性。

用 Hintsage AI 助手通过面试

答案。

三条规则:如果类管理资源(例如内存),则必须在显式实现以下方法之一时实现其余方法:

  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值运算符

C++11:五条规则 – 增加了移动操作:

  • 移动构造函数
  • 移动赋值运算符

违反此规则会导致资源所有权错误,例如双重删除或内存泄漏。

代码示例:

class Buffer { char* data; public: Buffer(size_t sz) : data(new char[sz]) {} ~Buffer() { delete[] data; } Buffer(const Buffer& other) : data(new char[strlen(other.data)+1]) { strcpy(data, other.data); } Buffer& operator=(const Buffer& other) { if (&other != this) { delete[] data; data = new char[strlen(other.data)+1]; strcpy(data, other.data); } return *this; } // C++11+ 中的移动语义: Buffer(Buffer&& other) noexcept : data(other.data) { other.data = nullptr; } Buffer& operator=(Buffer&& other) noexcept { if (&other != this) { delete[] data; data = other.data; other.data = nullptr; } return *this; } };

陷阱问题。

如果类管理指针,单单实现析构函数是否足够?

不够。没有拷贝和移动操作,复制时会发生双重内存删除。例如:

Buffer a(10); Buffer b = a; // b 和 a 将删除同一个指针!

由于对该主题细节的无知而产生的真实错误示例。


故事

在电信数据聚合平台上,所有类只实现了析构函数。重构结构后发生了大规模双重释放错误:对象复制会产生随机行为。


故事

在一款手机游戏项目中,忘记为缓冲区容器类实现移动构造函数。移动时对象被复制,导致数据额外复制和性能损失。


故事

在数据结构序列化库中,从函数返回对象时返回了临时对象,而拷贝构造函数进行了浅拷贝指针。导致了许多内存泄漏,直到几个月后才显现出来。