为什么C++中拷贝赋值运算符必须返回一个引用

这段代码展示了C++中拷贝赋值运算符的不同实现方式对效率的影响。通过对比class A和class B,可以看出直接返回值的拷贝赋值运算符会导致额外的临时对象创建和析构,从而降低效率。而class B的实现避免了这些额外开销,更受推崇。博客讨论了为何拷贝赋值运算符应返回引用以优化性能,并链接了一个Stack Overflow的相关讨论。
摘要由CSDN通过智能技术生成

通过一段代码说明这个问题

#include <iostream>

class A{
public:
    A() : m_age(0){ std::cout << "construvtor invoked." << std::endl; }
    A(const int age):m_age(age){
        std::cout << "int constructor invoked" << std::endl;
    }
    A(const A & rhs):m_age(rhs.m_age){
        std::cout << "copy constructor invoked." << std::endl;
    };
    A operator=(const A& rhs);
    ~A(){
        std::cout << "destructor invoked." << std::endl;
    }
private:
    int m_age = 0;
};
A A::operator=(const A &rhs) {
    std::cout << "copy assignment operator invoked." << std::endl;
    m_age = rhs.m_age;
    return *this;
}
class B{
public:
    B() : m_age(0){ std::cout << "construvtor invoked." << std::endl; }
    B(const int age):m_age(age){
        std::cout << "int constructor invoked" << std::endl;
    }
    B(const B & rhs):m_age(rhs.m_age){
        std::cout << "copy constructor invoked." << std::endl;
    };
    B& operator=(const B& rhs);
    ~B(){
        std::cout << "destructor invoked." << std::endl;
    }
private:
    int m_age = 0;
};
B& B::operator=(const B &rhs) {
    std::cout << "copy assignment operator invoked." << std::endl;
    m_age = rhs.m_age;
    return *this;
}
int main(void)
{
    std::cout << "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA" << std::endl;
    {
        A a1 = 1;
        A a2 = 2;
        A a3 = 3;
        {
            a1 = a2 = a3;
        }
        std::cout << "hello world" << std::endl;
    }

    std::cout << "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB" << std::endl;
    {
        B b1 = 1;
        B b2 = 2;
        B b3 = 3;
        {
            b1 = b2 = b3;
        }
        std::cout << "hello world" << std::endl;
    }
    return 0;
}

输出如下:

AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
int constructor invoked
int constructor invoked
int constructor invoked
copy assignment operator invoked.
copy constructor invoked.
copy assignment operator invoked.
copy constructor invoked.
destructor invoked.
destructor invoked.
hello world
destructor invoked.
destructor invoked.
destructor invoked.
BBBBBBBBBBBBBBBBBBBBBBBBBBBBB
int constructor invoked
int constructor invoked
int constructor invoked
copy assignment operator invoked.
copy assignment operator invoked.
hello world
destructor invoked.
destructor invoked.
destructor invoked.

Process finished with exit code 0

通过对比,发现:
如果拷贝赋值运算符重载直接返回值,也可以进行链式赋值,但是增加了很多徒劳无益的操作。额外调用了两次拷贝构造函数,两次析构函数,但是并没有因此而得到什么收益,因此不够高效。

原因在于,每一次调用=运算符,都会生成一个具有表达式作用域的临时对象,这个临时对象的生成需要调用拷贝构造函数,到达作用域的终点时又需要调用析构函数来释放内存空间。

反观class B,只执行了必要的操作,没有任何额外的函数调用,因此这种风格大家比较推崇。

贴一个SO的帖子:

https://stackoverflow.com/questions/3105798/why-must-the-copy-assignment-operator-return-a-reference-const-reference#:~:text=If%20you%20return%20a%20reference,assignment%20operator%20is%20called!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值