赋值运算符和复制构造函数有什么区别?


105

我不明白C ++中的赋值构造函数和复制构造函数之间的区别。就像这样:

class A {
public:
    A() {
        cout << "A::A()" << endl;
    }
};

// The copy constructor
A a = b;

// The assignment constructor
A c;
c = a;

// Is it right?

我想知道如何分配赋值构造函数和复制构造函数的内存吗?


2

Answers:


160

一个拷贝构造函数用于初始化一个先前未初始化的一些其他对象的数据对象。

A(const A& rhs) : data_(rhs.data_) {}

例如:

A aa;
A a = aa;  //copy constructor

一个赋值运算符是用来替换的数据之前初始化一些其他对象的数据对象。

A& operator=(const A& rhs) {data_ = rhs.data_; return *this;}

例如:

A aa;
A a;
a = aa;  // assignment operator

您可以将副本构造替换为默认构造加上分配,但这会降低效率。

(作为附带说明:上面的实现正是编译器免费授予您的实现,因此手动实现它们没有多大意义。如果您拥有这两种实现之一,则可能是您在手动管理某些资源。在这种情况下,按照“三则规则”,您很可能还需要另一个加一个析构函数。)


4
请注意:如今(从C ++ 11开始),可以使用显式默认它们=default;
重复数据删除器2014年

2
@Deduplicator还必须提及的是,在坚持需要琐碎构造函数的分类时,必须 = default在需要默认ctor的地方将它们分类:仅靠我们自己实现一个空主体仍然算作用户定义的ctor,因此(在Standardese级别上) )并非无关紧要,并且会从需要普通ctor的分类中取消类型的资格。
underscore_d

@sbi我可以说在不使用复制构造函数而使用赋值运算符的情况下,首先通过调用带参数或不带参数的构造函数来创建对象,然后使用赋值运算符并基于RHS分配新值。如果使用了复制构造函数,则仍将调用相同的构造函数,但用于初始化的值来自其他对象。
拉耶什

@Rajesh:我对您的要求感到困惑,我的感觉是因为您也感到困惑。:)您会再次尝试解释您在说什么吗?
sbi

1
@CătălinaSîrbu:可以。它们是两个独立的功能。
sbi

41

复制构造函数和赋值运算符之间的差异给新程序员带来了很多困惑,但实际上并不是那么困难。总结:

  • 如果必须在复制发生之前创建一个新对象,则使用复制构造函数。
  • 如果在复制发生之前不必创建新对象,则使用赋值运算符。

赋值运算符的示例:

Base obj1(5); //calls Base class constructor
Base obj2; //calls Base class default constructor
obj2 = obj1; //calls assignment operator

复制构造函数示例:

Base obj1(5);
Base obj2 = obj1; //calls copy constructor

可以公平地说,赋值运算符将旧对象的销毁与新对象的创建有效地结合在一起,但有以下条件:(1)如果旧对象销毁的步骤之一将被撤销新的步骤之一,可以省略这两个步骤;(2)如果将对象分配给自身,则赋值运算符不应做坏事。
2013年

为什么这样做vector <A> v3,然后v3 = v2 v2先前声明并包含元素的位置vector<A>调用我的显式A的副本构造函数而不是operator=我期待operator=被调用,而不是copy constructor因为我的v3目标在那里我做了分配的时间已经宣布
卡特琳娜瑟尔布

19

第一个是复制初始化,第二个是赋值。没有赋值构造函数之类的东西。

A aa=bb;

使用编译器生成的副本构造函数。

A cc;
cc=aa;

使用默认的构造函数来构造cc,然后使用* assignment运算符**(operator =)对已经存在的对象进行构造。

我想知道如何分配赋值构造函数和复制构造函数的内存吗?

在这种情况下,IDK是指分配内存的意思,但是如果您想知道会发生什么,则可以:

class A
{
public :
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

我还建议您看一下:

为什么调用复制构造函数而不是转换构造函数?

什么是三法则?


5

简单来说

从现有对象创建新对象作为现有对象的副本时,将调用复制构造函数。当已初始化的对象从另一个现有对象分配了新值时,将调用赋值运算符。

例-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"

4

@Luchian Grigore Said的实现是这样的

class A
{
public :
    int a;
    A(){ cout<<"default constructor"<<endl;};
    A(const A& other){ cout<<"copy constructor"<<endl;};
    A& operator = (const A& other){cout <<"assignment operator"<<endl;}
};

void main()
{
    A sampleObj; //Calls default constructor
    sampleObj.a = 10;

    A copyConsObj  = sampleObj; //Initializing calls copy constructor

    A assignOpObj; //Calls default constrcutor
    assignOpObj = sampleObj; //Object Created before so it calls assignment operator
}

输出值


默认构造函数


复制构造函数


默认构造函数


赋值运算符



4

复制构造函数和赋值构造函数之间的区别是:

  1. 在拷贝构造函数的情况下,它会创建一个新的对象。( <classname> <o1>=<o2>
  2. 对于赋值构造函数,它将不会创建任何对象,这意味着它将应用于已创建的object(<o1>=<o2>)。

而且两者的基本功能都相同,它们会将数据从o2逐个成员复制到o1。


2

我想在这个话题上再加一点。“赋值运算符的运算符功能应仅作为类的成员函数编写。” 与其他二进制或一元运算符不同,我们不能将其作为好友函数。


1

关于复制构造函数的一些补充:

  • 当按值传递对象时,它将使用复制构造函数

  • 从函数按值返回对象时,它将使用复制构造函数

  • 使用另一个对象的值初始化一个对象时(作为示例)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.