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

What's the difference between assignment operator and copy constructor?

提问人:alan.chen 提问时间:7/29/2012 最后编辑:Cœuralan.chen 更新时间:4/15/2021 访问量:119356

问:

我不明白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?

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

C++ 内存

评论

0赞 fredoverflow 7/29/2012
相关常见问题

答:

23赞 Luchian Grigore 7/29/2012 #1

第一个是副本初始化,第二个只是赋值。没有赋值构造函数这样的东西。

A aa=bb;

使用编译器生成的复制构造函数。

A cc;
cc=aa;

使用默认构造函数构造 ,然后在已存在的对象上使用 *赋值运算符** ()。ccoperator =

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

在这种情况下,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;}
};

我还建议你看看:

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

什么是三分法则?

248赞 sbi 7/29/2012 #2

复制构造函数用于从其他对象的数据初始化以前未初始化的对象。

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

您可以用默认的构造加赋值来替换复制构造,但这样做会降低效率。

(顺便说一句:我上面的实现正是编译器免费授予你的实现,所以手动实现它们没有多大意义。如果您拥有这两个资源之一,则可能是手动管理某些资源。在这种情况下,根据三法则,您很可能还需要另一个加上析构函数。

评论

6赞 Deduplicator 7/19/2014
请注意:现在(C++11 以后),它们可以显式默认为 .=default;
3赞 underscore_d 7/12/2016
@Deduplicator 值得一提的是,当坚持需要简单构造函数的分类时,您必须在需要默认 ctor 的地方使用它们:简单地由我们自己实现一个空体仍然算作用户定义的 ctor,因此(在标准级别上)不是微不足道的,并且使该类型不符合需要简单 ctor 的分类。= default
0赞 Rajesh 3/17/2018
@sbi 我可以说,如果不使用复制构造函数而使用赋值运算符,则首先通过调用带参数或不带参数的构造函数来创建对象,然后使用赋值运算符并根据 RHS 分配新值。如果使用复制构造函数,则仍将调用相同的构造函数,但用于初始化的值来自其他对象。
1赞 sbi 1/21/2020
@CătălinaSîrbu:可以。它们是两个独立的功能。
1赞 sbi 11/20/2020
@LiamClink:这是不对的。初始化意味着通过将可感知的字节写入该内存块,将一块原始内存转换为格式正确的对象。复制构造允许您从一开始就写入正确的字节,而不是首先默认初始化对象,然后必须通过赋值覆盖它。
53赞 Arun 7/23/2013 #3

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

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

赋值运算符示例:

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

评论

0赞 supercat 7/24/2013
公平地说,赋值运算符有效地将旧对象的销毁与新对象的创建结合起来,但附带条件是:(1)如果销毁旧对象的某个步骤将被构建新对象的步骤之一所撤销, 这两个步骤都可以省略;(2) 如果一个对象被赋值给自己,赋值运算符不应该做坏事。
1赞 Cătălina Sîrbu 4/15/2020
为什么做然后(其中 v2 是先前声明并包含元素 vector<A>调用我的显式复制构造函数而不是?我期望调用 operator= 而不是复制构造函数,因为我的 v3 对象在我执行赋值时已经声明vector <A> v3v3 = v2Aoperator=
4赞 Mak 3/3/2014 #4

格里戈里·赛义德(Grigore Said@Luchian是这样实现的

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
}

输出


Default 构造函数


Copy 构造函数


Default 构造函数


赋值运算符


6赞 Nitesh Kumar 1/1/2016 #5

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

  1. 如果是复制构造函数,它会创建一个新对象。(<classname> <o1>=<o2>)
  2. 如果是赋值构造函数,它不会创建任何对象,这意味着它适用于已经创建的对象()。<o1>=<o2>

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

1赞 Frank Shen 1/24/2016 #6

关于复制构造函数要添加的一些东西:

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

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

  • 使用另一个对象的值初始化一个对象时(如您给出的示例)。

9赞 dev 2/20/2017 #7

简单来说,

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

例-

t2 = t1;  // calls assignment operator, same as "t2.operator=(t1);"
Test t3 = t1;  // calls copy constructor, same as "Test t3(t1);"
2赞 MD BELAL RASHID 8/19/2017 #8

我想就这个话题再补充一点。 “赋值运算符的运算符函数只能写为类的成员函数。”我们不能像其他二进制或一元运算符那样将其作为友元函数。