赋值运算符和复制构造函数有啥区别?
Posted
技术标签:
【中文标题】赋值运算符和复制构造函数有啥区别?【英文标题】:What's the difference between assignment operator and copy constructor?赋值运算符和复制构造函数有什么区别? 【发布时间】:2012-07-27 05:00:12 【问题描述】:我不明白 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?
我想知道赋值构造函数和拷贝构造函数的内存如何分配?
【问题讨论】:
related FAQ 【参考方案1】:复制构造函数用于从其他对象的数据初始化以前未初始化的对象。
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
您可以通过默认构造加赋值来替换复制构造,但这会降低效率。
(附带说明:我上面的实现正是编译器免费授予您的实现,因此手动实现它们没有多大意义。如果您有这两者之一,很可能您正在手动管理一些资源。在这种情况下,根据 The Rule of Three,你很可能还需要另一个加上一个析构函数。)
【讨论】:
请注意:如今(C++11 以后),它们可以显式默认为=default;
。
@Deduplicator 同样重要的是要提到,当坚持需要琐碎构造函数的分类时,您必须 = default
在需要默认 ctor 的地方:简单地实现一个空body 本身仍然算作用户定义的 ctor,因此(在标准层面上)不是微不足道的,并且使该类型不符合需要微不足道 ctor 的分类的资格。
@sbi 我可以说,如果不使用复制构造函数而是使用赋值运算符,则首先通过调用带参数或不带参数的构造函数创建对象,然后使用赋值运算符和新值根据 RHS 分配。如果使用复制构造函数,仍然会调用相同的构造函数,但用于初始化的值来自其他对象。
@Rajesh:我对你在问什么感到困惑,我的感觉是因为你也很困惑。 :)
你能再解释一下你在说什么吗?
@CătălinaSîrbu:你可以。它们是两个独立的函数。【参考方案2】:
复制构造函数和赋值运算符之间的区别会给新手程序员带来很多困惑,但实际上并没有那么困难。总结:
如果必须在复制之前创建新对象,则使用复制构造函数。 如果在复制之前不必创建新对象,则使用赋值运算符。赋值运算符示例:
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) 如果一个对象被赋值给自己,赋值运算符不应该做坏事。 为什么要先vector <A> v3
然后v3 = v2
(其中v2
是先前声明并包含元素vector<A>
) 调用我的显式A
的副本构造函数而不是 operator=
? 我希望调用 operator=
而不是 copy constructor
,因为我的 v3
对象在我执行分配时已经声明了【参考方案3】:
第一个是复制初始化,第二个只是赋值。没有赋值构造函数之类的东西。
A aa=bb;
使用编译器生成的复制构造函数。
A cc;
cc=aa;
使用默认构造函数构造cc
,然后在已经存在的对象上使用*赋值运算符** (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;
;
我也建议你看看:
Why is copy constructor called instead of conversion constructor?
What is The Rule of Three?
【讨论】:
【参考方案4】:简单来说,
从现有对象创建新对象时调用复制构造函数,作为现有对象的副本。 当一个已经初始化的对象从另一个现有对象分配一个新值时,就会调用赋值运算符。
例子-
t2 = t1; // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1; // calls copy constructor, same as "Test t3(t1);"
【讨论】:
【参考方案5】:@Luchian Grigore 所说的就是这样实现的
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
输出
默认构造函数
复制构造函数
默认构造函数
赋值运算符
【讨论】:
【参考方案6】:复制构造函数和赋值构造函数的区别是:
-
如果是复制构造函数,它会创建一个新对象。(
<classname> <o1>=<o2>
)
如果是赋值构造函数,它不会创建任何对象,这意味着它适用于已创建的对象(<o1>=<o2>
)。
两者的基本功能是相同的,都是将数据从o2逐个成员复制到o1。
【讨论】:
【参考方案7】:我想就这个话题再补充一点。 “赋值运算符的运算符函数只能写为类的成员函数。”与其他二元或一元运算符不同,我们不能将其作为友元函数。
【讨论】:
【参考方案8】:关于复制构造函数的补充:
按值传递对象时,会使用复制构造函数
当一个对象从函数中按值返回时,会使用复制构造函数
使用另一个对象的值初始化一个对象时(如您给出的示例)。
【讨论】:
以上是关于赋值运算符和复制构造函数有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章