三/五法则

当定义一个类时,我们显式地或隐式地指定了此类型的对象在拷贝、赋值和销毁时做什么。一个类通过定义三种特殊的成员函数来控制这些操作:拷贝构造函数拷贝赋值运算符析构函数

  1. 拷贝构造函数定义了当用同类型的另一个对象初始化新对象时做什么
  2. 拷贝赋值运算符定义了将一个对象赋予同类型的另一个对象时做什么
  3. 析构函数定义了此类型的对象销毁时做什么。

我们将这些操作称为拷贝控制操作

由于拷贝控制操作是由三个特殊的成员函数来完成的,所以我们称此为“C++三法则”。在较新的 C++11 标准中,为了支持移动语义,又增加了移动构造函数和移动赋值运算符,这样共有五个特殊的成员函数,所以又称为“C++五法则”。

也就是说,“三法则”是针对较旧的 C++89 标准说的,“五法则”是针对较新的 C++11 标准说的。
为了统一称呼,后来人们把它叫做“C++ 三/五法则”。

法则一、需要析构函数的类也需要拷贝构造和拷贝赋值函数”

从“需要析构函数”可知,类中必然出现了指针类型的成员(否则不需要我们写析构函数,默认的析构函数就够了),所以,我们需要自己写析构函数来释放给指针所分配的内存来防止内存泄漏。

那么为什么说也需要拷贝构造和拷贝赋值函数呢?

原因是:类中出现了指针类型的成员,必须防止浅拷贝问题。所以需要自己书写拷贝构造函数和拷贝赋值运算符,而不能使用默认的拷贝构造函数和默认的拷贝赋值运算符。

法则二、需要拷贝操作的类也需要赋值操作,反之亦然”

为啥?因为拷贝赋值操作实际上是 析构+拷贝 所以拷贝需要做的,赋值也需要做同样的事

法则三、析构函数不能是删除的成员

如果析构函数是删除的(即析构函数被声明为= delete),那么无法销毁此类型的对象。
对于一个删除了析构函数的类型,编译器不允许定义该类型的变量或创建该类的临时对象。而且,如果一个类有某个成员的类型删除了析构函数,我们也不能定义该类的变量或临时对象。

在需要特殊设计的情况下,可以把析构函数设为private的。此时一定要提供一个static destroy函数,否则将造成内存泄漏。但是这样需要手动管理资源,其实也是非常不推荐的。

为什么我们需要三五法则?

三/五法则的核心是确保资源的安全管理生命周期可控。若析构函数不可用(删除或私有):

  • 拷贝和移动操作失效:即使定义了拷贝构造函数或移动构造函数,若无法销毁对象,资源最终仍会泄漏。
  • 破坏 RAII 机制:C++ 依赖析构函数自动释放资源,手动管理易出错。

现在,我们应当怎么做?

随着时间的流逝,C++语言也在不断成长,在C++11标准下,我们最好:

  • 优先使用智能指针和容器,减少手动资源管理。
  • 若必须手动管理资源,严格遵循三/五法则,确保析构、拷贝、移动操作正确实现。