c++析构函数可以使一个return-by-value的函数少执行一次拷贝构造函数,是什么原因?

发布于 2022-09-01 23:36:36 字数 1008 浏览 21 评论 0

#include <iostream>
using namespace std;
int cnt = 0;
class CTest1 {
public:
    CTest1()
    {
        id = cnt;
        cout<<"Constructor of CTest1:" <<id <<endl;
        cnt++;
    }
    CTest1(const CTest1& a)
    {
        id = cnt;
        cout<<"Copy constructor of CTest1:" << id <<endl;
        cnt++;
    }
    CTest1& operator=(CTest1& a)
    {
        cout << " assign operator of CTest1:" << id << endl;
        return *this;
    }
//    ~CTest1()
//    {
//        cout << " destroy id:" << id << endl;
//    }
//去掉析构函数的注释,则程序只会执行2次拷贝构造函数
    int id;
};
CTest1 getTestObj(CTest1 obj)
{
    return obj;
}

int main()
{
    CTest1 a1;            
    CTest1 a2 = getTestObj(a1);
    return 0;
}

图片描述

左边的结果是注释了析构函数的结果,右边是去掉了注释。可以看到若注释了析构函数,就会调用多一次拷贝构造函数,为何?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦明 2022-09-08 23:36:36

原因在于优化.
先来分析你的程序, a1是一个实例, a2是一个, getTest传参是传值那么会有一个Temp1, getTest又有一个return Temp2. 所以一共应该是四个对象.

但是, 编译器会有优化, 甚至在你禁止优化的时候也会有一点点优化. 比如getTest的返回值, 本来按照语义是需要调用operator=, 实际上编译器通常是直接调用CTest1(const CTest1&)这个构造函数, 把两次构造优化成1次.

你那个代码, 把析构函数里面的cout注释掉, 就会发现只构造了3次. 因为析构函数里面什么都没有的话, 编译器开启那个优化, 对你的代码功能上就没有任何影响. 但是你开cout的话, 一旦优化掉的话, 代码的功能可能就不正确了.

你删掉析构函数里面的cout, 用gcc编译, 添加参数-O0 -fno-elide-constructors, 实际上还是四个对象.

海螺姑娘 2022-09-08 23:36:36
CTest1 getTestObj(CTest1 obj)
{
    return obj; /* copy */
}

int main()
{
    CTest1 a1; // construct             
    CTest1 a2 = /* copy */ getTestObj(a1/* copy */);
    return 0;
}

关于返回值有一种对编译器来说省事的方式,叫做返回值优化(RVO - return value optimization)。编译器会省略一步对象的COPY构造调用,不知道LZ用的什么编译器,在gcc(4.8.3)上面是默认开启的,就是说结果是这样的:

Constructor of CTest1:0
Copy constructor of CTest1:1
Copy constructor of CTest1:2
//如果去掉注释 就会打印下面三句话
 destroy id:1 
 destroy id:2
 destroy id:0
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文