C++ 中的三法则与五法则?
三法则是在使用 C++ 时的一条经验法则。这是一种良好的实践规则,它指出如果你的类需要以下任何一个:
- a. 复制构造函数,
- b. 赋值运算符,
- c. 析构函数,
显式定义,那么它很可能需要这三个中的所有。
为什么是这样?因为,如果你的类需要上述任何一个,它就是在管理动态分配的资源,并且很可能需要其他两个来成功实现这一点。例如,如果你需要一个赋值运算符,你将创建正在通过引用复制的对象的副本,从而分配资源。你需要复制构造函数进行复制,并需要析构函数释放这些资源。
五法则由于 C++11 中引入了移动语义,它是三法则的扩展。五法则也应用于 C++ 中的资源管理。此规则可以消除 C++ 代码中的内存泄漏和其他问题。五法则指出,如果你必须编写以下函数之一,那么你必须对所有这些函数制定策略。如果我们有一个对象 Foo,那么我们可以有一个 FooManager 来处理资源 Foo。在实现 FooManager 时,你很可能需要实现以下所有函数:
析构函数 - 当此管理器超出范围时,它应该释放它正在管理的所有资源。
赋值运算符 - 如果你不提供一个,编译器会创建一个默认的赋值运算符。默认赋值操作是一个逐成员复制函数,执行浅拷贝而不是深拷贝。这可能会导致内存泄漏、错误赋值等问题。
复制构造函数 - 编译器提供的复制构造函数会逐成员复制所有 FooManager 属性。这会带来与赋值运算符相同的问题。
移动构造函数 - 复制对象可能代价高昂,因为它涉及创建、复制然后销毁临时对象。C++11 引入了右值引用的概念。右值引用可以显式绑定到右值。右值是未命名的对象。换句话说,就是临时对象。此右值引用可用于构造函数中,以创建对传递给它的右值的引用。
移动构造函数 - 复制对象可能代价高昂,因为它涉及创建、复制然后销毁临时对象。C++11 引入了右值引用的概念。右值引用可以显式绑定到右值。右值是未命名的对象。换句话说,就是临时对象。此右值引用可用于构造函数中,以创建对传递给它的右值的引用。
移动赋值运算符 - 一次只拥有一个资源很有用。此资源的所有权可以从一个管理器转移到另一个管理器。在这种情况下,你可以提供一个移动赋值运算符。
这是一个了解五法则的好资源 - https://www.feabhas.com/sites/default/files/2016-06/Rule%20of%20the%20Big%20Five.pdf.