C++中拷贝对象时编译器做出的一些优化

目录

拷贝对象时编译器做出的一些优化

参数传递优化

返回值优化


拷贝对象时编译器做出的一些优化

📌

下面的优化结果由编译器决定,不同的编译器优化结果可能不同,视具体情况而定

参数传递优化

  1. 在前面的explicit关键字部分提到过编译器会对在单行的构造+拷贝构造优化为构造
#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {}

    void print()
    {
        cout << _num << endl;
    }
};

int main()
{
    test t = 1;
    t.print();
    return 0;
}
输出结果:
1
  1. 在给函数形参传递实参时,如果直接传递已经创建的对象时,编译器不会对其进行优化
#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

void func1(const test t)
{
    cout << "func1" << endl;
}

int main()
{
    test t1(1);
    func1(t1);
    return 0;
}
输出结果:
构造函数
拷贝构造函数
func1
析构函数
析构函数

在上面的代码中,首先test类创建了一个对象为t1,此时调用构造函数,当t1作为函数实参传递给func1函数,此时会调用拷贝构造函数将t1对象拷贝给形参t,接着进入func1函数栈帧空间执行func1函数体的语句,当func1函数结束执行后调用析构函数销毁形式参数对象t,最后调用析构函数销毁局部对象t1

对上面的代码进行改进,直接传递整型1给func1函数,如下面代码

#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

void func1(const test t)
{
    cout << "func1" << endl;
}

int main()
{
    func1(1);
    return 0;
}
输出结果:
构造函数
func1
析构函数

在上面的代码中,直接将1作为对象传递给自定义类型的形参t时,常规的步骤为:调用构造函数用整型1初始化一个临时对象,再调用拷贝构造函数将临时对象中的内容拷贝给形参对象,但是此处编译器会对其进行优化为直接调用构造函数,用整型1初始化形参对象t

同理,使用匿名对象作为实际参数传递给自定义类型的形参时,编译器也会有所优化

#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

void func1(const test t)
{
    cout << "func1" << endl;
}

int main()
{
    func1(test(2));

    return 0;
}
输出结果:
构造函数
func1
析构函数

在上面的代码中,使用整型2创建了一个匿名对象,常规步骤为:调用构造函数使用整型2创建匿名对象,接着调用拷贝构造函数将匿名对象中的内容拷贝给形式参数,但是编译器优化为直接使用整型2为形式参数初始化

但是如果函数的形式参数为引用时,则不会有任何优化,直接调用构造函数进行初始化对象再由自定义类型的引用形参接收实参对象的地址

📌

注意:使用引用传参时一定要在形式参数处加const修饰

#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

void func1(const test& t)
{
    cout << "func1" << endl;
}

int main()
{
    test t1(1);
    func1(t1);
    cout << endl;
    func1(1);
    cout << endl;
    func1(test(1));

    return 0;
}
输出结果:
构造函数
func1

构造函数
func1
析构函数

构造函数
func1
析构函数
析构函数

返回值优化

#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    test& operator=(const test& t)
    {
        cout << "赋值运算符重载函数" << endl;
        if (this != &t)
        {
            _num = t._num;
        }
        return *this;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

test func()
{
    cout << "func" << endl;
    test t(1);
    return t;
}

int main()
{
    func();

    return 0;
}
  1. 当调用的函数有返回对象时,使用该对象初始化对象
#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test(int num)
        :_num(num)
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    test& operator=(const test& t)
    {
        cout << "赋值运算符重载函数" << endl;
        if (this != &t)
        {
            _num = t._num;
        }
        return *this;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

test func()
{
    cout << "func" << endl;
    test t(1);
    return t;
}

int main()
{
    test t1 = func();

    return 0;
}

在上面的代码中,使用func函数的返回值初始化t1对象,常规的过程为:调用拷贝构造函数将func函数的返回值放入一个自定义类型的临时变量中,再通过拷贝构造函数将临时变量中的内容拷贝给t1对象,但是这里编译器会优化为调用一个构造函数将func的返回值作为初始化值直接初始化t1对象

但是如果将两个步骤分开,如下面的代码

#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test()
        :_num()
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    test& operator=(const test& t)
    {
        cout << "赋值运算符重载函数" << endl;
        if (this != &t)
        {
            _num = t._num;
        }
        return *this;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

test func()
{
    cout << "func" << endl;
    test t;
    return t;
}

int main()
{
    test t1;
    t1 = func();
    return 0;
}

在上面的代码中,因为t1对象需要完成实例化,所以会调用构造函数,接着执行t1 = func()语句,因为赋值运算符有从右往左的结合性,所以先执行func函数,在func函数中会再次调用构造函数创建一个对象,(注意中间有一个过程为:调用拷贝构造将返回对象拷贝到临时对象中,再调用析构函数销毁局部对象t)此时执行赋值语句,此时调用赋值运算符重载函数,将t对象的内容给t1对象

  1. 当返回的是匿名对象,使用该匿名对象初始化对象
#include <iostream>
using namespace std;

class test
{
private:
    int _num;
public:
    test()
        :_num()
    {
        cout << "构造函数" << endl;
    }

    void print()
    {
        cout << _num << endl;
    }

    test(const test& t)
    {
        _num = t._num;
        cout << "拷贝构造函数" << endl;
    }

    test& operator=(const test& t)
    {
        cout << "赋值运算符重载函数" << endl;
        if (this != &t)
        {
            _num = t._num;
        }
        return *this;
    }

    ~test()
    {
        cout << "析构函数" << endl;
    }
};

test func()
{
    cout << "func" << endl;
    return test();
}

int main()
{
    test t1 = func();
    return 0;
}
输出结果:
func
构造函数
析构函数

在上面的代码中,先执行func函数,常规步骤为:执行test类中的构造函数创建一个匿名对象,接着调用拷贝构造将匿名对象拷贝到临时对象中返回,接着调用拷贝构造将返回值拷贝给t1对象,但是此处编译器会优化为直接用返回的匿名对象的内容作为初始值初始化对象t1

总结:

  1. 为了编译器更好得优化,在传参数时,可以考虑使用引用变量作为参数
  2. 当使用到返回值时,如果能用引用就使用引用,不能使用引用需要返回值时,可以考虑返回匿名对象

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怡晗★

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值