复制构造函数和赋值运算符

The copy constructor and assignment operator

提问人:Paul Manta 提问时间:3/20/2011 最后编辑:mpmPaul Manta 更新时间:6/28/2021 访问量:83539

问:

如果我重写,复制构造函数会自动使用 new 运算符吗?同样,如果我定义一个复制构造函数,会自动从复制构造函数“继承”行为吗?operator=operator=

C++ 构造函数 复制构造函数 赋值运算符

评论

0赞 Saurabh Gokhale 3/20/2011
看看这个链接:stackoverflow.com/questions/1457842/... &stackoverflow.com/questions/1477145/...
0赞 fredoverflow 3/20/2011
什么是三法则的可能副本?

答:

13赞 Erik 3/20/2011 #1

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

0赞 Jonathan Wood 3/20/2011 #2

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

57赞 Saurabh Gokhale 3/20/2011 #3

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

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

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

有用的链接:

评论

0赞 Alcott 9/12/2011
@Prasoon,我不太明白,当按值将变量传递到函数中或作为函数的返回值时,为什么不调用复制构造函数?什么是 RVO?
0赞 Ghita 11/16/2012
@Alcottreturn价值优化
0赞 jupp0r 1/27/2016
还有复制省略,它对函数参数做同样的事情
1赞 stijn 3/20/2011 #4

不。

一定要看看法则(或考虑右值时的五法则

5赞 Alexandre C. 3/20/2011 #5

不。它们是不同的对象。

如果您担心复制构造函数和赋值运算符之间的代码重复,请考虑以下习惯用语,称为 copy 和 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;
    }
};

这样,将使用 copy 构造函数来构建一个新对象,该对象将在函数退出时与旧对象交换并释放(内部有旧对象)。operator=*thisthis

评论

0赞 Alcott 9/12/2011
通过引用复制和交换的习惯,您是否暗示在 copy-ctor 中调用 operator= 不是一个好做法,反之亦然?
0赞 Alexandre C. 9/13/2011
@Alcott:你不要在复制构造函数中调用 operator=,而是反过来做,就像我展示的那样。
0赞 Johan Boulé 5/8/2016
为什么你的赋值运算符不采用常量引用?
0赞 Alexandre C. 5/8/2016
@JohanBoule:这在我的回答的维基百科链接中得到了解释,这个问题也解释了
1赞 Ray Cao 3/11/2021 #6

请考虑以下 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::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 中,对象已经存在(我们已经完成了:)。复制构造函数和复制赋值运算符之间有两个明显的区别。v3Vector v3{10};

  • 复制构造函数 无需删除旧元素,它只是一个新对象。(因为它copy constructVector v2)
  • copy 构造函数 NO NEED to return the pointer。(此外,所有构造函数都不返回值)。this