📜  C++中的三法则

📅  最后修改于: 2021-05-30 02:21:48             🧑  作者: Mango

该规则基本上表明,如果一个类定义了以下一个(或多个),则它可能应该显式定义所有三个,即:

  • 析构函数
  • 复制构造函数
  • 复制分配运算符

现在让我们试着理解为什么?
默认的构造函数和赋值运算符执行浅表复制,当我们需要深度复制时(例如,当类包含指向动态分配的资源的指针时),我们将创建自己的构造函数和赋值运算符

首先,析构函数做什么?它包含应该在对象被销毁时运行的代码。只影响对象的内容将是无用的。在销毁过程中的对象不能对其进行任何更改。因此,析构函数会影响整个程序的状态。

现在,假设我们的类没有副本构造函数。然后,复制对象会将其所有数据成员复制到目标对象。这些物体被摧毁时会发生什么?析构函数运行两次。而且,析构函数具有可用于每个被破坏对象的相同信息。总结起来,在没有复制构造函数的情况下,析构函数的执行应该发生一次,而执行两次。这种重复执行是麻烦的根源。

编码示例如下:

// In the below C++ code, we have created
// a destructor, but no copy constructor
// and no copy assignment operator.
class Array
{
private:
    int size;
    int* vals;  
   
public:
    ~Array();
    Array( int s, int* v );
};
   
Array::~Array()
{
   delete vals;
   vals = NULL;
}
   
Array::Array( int s, int* v )
{
    size = s;
    vals = new int[ size ];
    std::copy( v, v + size, vals );
}
   
int main()
{
   int vals[ 4 ] = { 11, 22, 33, 44 }; 
   Array a1( 4, vals );
  
   // This line causes problems.
   Array a2( a1 );
  
   return 0;
}

在上面的示例中,程序超出范围后,将调用类析构函数,而不是调用一次,而是调用两次。首先是由于a1的删除,然后是a2的删除。默认的复制构造函数复制指针vals ,并且实际上不为其分配内存。因此,删除a1时,析构函数将释放vals 。试图被析构函数删除时,包含实例的所有后续val都会导致程序崩溃,因为val不再存在。

复制分配运算符的情况与此类似。如果一个类没有显式定义的赋值运算符,则将所有源数据成员隐式分配给目标的相应数据成员。总而言之,它创建了一个副本,这又是先前定义的相同问题。

参考:

  • https://zh.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
  • http://www.drdobbs.com/c-made-easier-the-rule-of-three/184401400
要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”