【问题标题】:The copy constructor and assignment operator复制构造函数和赋值运算符
【发布时间】:2011-07-19 02:28:44
【问题描述】:

如果我覆盖operator=,复制构造函数会自动使用new 运算符吗?同样,如果我定义了一个拷贝构造函数,operator= 会自动“继承”拷贝构造函数的行为吗?

【问题讨论】:

标签: c++ constructor operators copy-constructor assignment-operator


【解决方案1】:

不,它们是不同的运算符。

复制构造函数用于创建一个新对象。它将现有对象复制到新构造的对象。复制构造函数用于从旧实例初始化新实例 实例。将变量按值传递给函数时不一定会调用它 或作为函数的返回值。

赋值运算符是处理一个已经存在的对象。赋值运算符用于将现有实例更改为 与右值相同的值,这意味着实例必须是 如果它有内部动态内存,则销毁并重新初始化。

有用的链接:

【讨论】:

  • ...is called when passing variables by value into functions or as return values out of functions. 不一定。由于 RVO,当您按值返回时,可能不会调用复制构造函数。
  • @PS:+1 ...谢谢!已编辑!
  • @Prasoon,我不太明白,当按值将变量传递给函数或作为函数的返回值时,为什么不能调用复制构造函数?什么是 RVO?
  • @Alcottreturn 值优化
  • 还有复制省略,对函数参数也是如此
【解决方案2】:

没有。除非您定义复制 ctor,否则将生成默认值(如果需要)。除非您定义 operator=,否则将生成默认值(如果需要)。它们不相互使用,您可以独立更改它们。

【讨论】:

    【解决方案3】:

    没有。它们是不同的对象。

    如果您担心复制构造函数和赋值运算符之间的代码重复,请考虑以下成语,命名为 copy and swap

    struct MyClass
    {
        MyClass(const MyClass&); // Implement copy logic here
        void swap(MyClass&) throw(); // Implement a lightweight swap here (eg. swap pointers)
    
        MyClass& operator=(MyClass x)
        {
            x.swap(*this);
            return *this;
        }
    };
    

    这样,operator= 将使用复制构造函数来构建一个新对象,该对象将与*this 交换并在函数退出时释放(其中包含旧的this)。

    【讨论】:

    • 通过引用 copy-and-swap 习语,您是否暗示在 copy-ctor 中调用 operator= 不是一个好习惯,反之亦然?
    • @Alcott:您不会在复制构造函数中调用 operator=,而是以相反的方式调用,就像我展示的那样。
    • 为什么你的赋值运算符不使用 const 引用?
    • @JohanBoule:我的回答中的*链接以及this question对此进行了解释
    【解决方案4】:

    没有。

    一定要看看the rule of three (或rule of five 考虑右值)

    【讨论】:

      【解决方案5】:

      考虑以下 C++ 程序。
      注意:我的“Vector”类不是标准库中的那个。
      我的“Vector”类接口

      #include <iostream>
      
      class Vector {
      private:
          double* elem; // elem points to an array of sz doubles
          int sz;
      public:
          Vector(int s);  // constructor: acquire resources
          ~Vector() { delete[] elem; }   // destructor: release resources
          Vector(const Vector& a);               // copy constructor
          Vector& operator=(const Vector& a);    // copy assignment operator
          double& operator[](int i){ return elem[i]; };
          int size() const {return sz;};
      };
      

      我的“向量”类成员实现

      Vector::Vector(int s)  // non-default constructor
      {
          std::cout << "non-default constructor"<<std::endl;
          elem = {new double[s]};
          sz =s;
          for (int i=0; i!=s; ++i)      // initialize elements
              elem[i]=0;
      }
      
      Vector::Vector(const Vector& a)   // copy constructor
              :elem{new double[a.sz]},
               sz{a.sz}
      {
          std::cout << "copy constructor"<<std::endl;
          for (int i=0; i!=sz; ++i)    // copy elements
              elem[i] = a.elem[i];
      }
      
      Vector& Vector::operator=(const Vector& a)     // copy assignment operator
      {
          std::cout << "copy assignment operator"<<std::endl;
          double* p = new double[a.sz];
          for (int i=0; i!=a.sz; ++i)
              p[i] = a.elem[i];
          delete[] elem;         // delete old elements
          elem = p;
          sz = a.sz;
          return *this;
      }
      
      int main(){
          Vector v1(1);
          v1[0] = 1024;    // call non-default constructor
         
          Vector v2 = v1;   // call copy constructor  !!!!
      
          v2[0] = 1025;
          std::cout << "v2[0]=" << v2[0] << std::endl;
      
          Vector v3{10};  // call non-default constructor
          std::cout << "v3[0]=" << v3[0] << std::endl;
      
          v3 = v2;     // call copy assignment operator  !!!!
          std::cout << "v3[0]=" << v3[0] << std::endl;
      }
      

      然后,程序输出:

      non-default constructor
      copy constructor
      v2[0]=1025
      non-default constructor
      v3[0]=0
      copy assignment operator
      v3[0]=1025
      

      总结

      1. Vector v2 = v1; 导致调用复制构造函数。
      2. v3 = v2; 导致调用复制赋值运算符。

      在情况 2 中,对象 v3 已经存在(我们已经完成:Vector v3{10};)。拷贝构造函数和拷贝赋值运算符有两个明显的区别。

      • 复制构造函数不需要删除旧元素,它只是copy construct一个新对象。 (因为它Vector v2
      • 复制构造函数不需要返回this指针。(此外,所有构造函数都不返回值)。

      【讨论】:

        【解决方案6】:

        不,它们不是同一个运算符。

        【讨论】: