【C++深度解析】15、避免临时对象

1 临时对象的产生

1.1 产生了临时对象

首先,我们先看一段代码,我们使用带参数的构造函数实现不带参数的构造函数

//15-1.cpp
#include<stdio.h>
class Test
{
public:
    Test(int i) : x(i){}
    Test()
    {
        Test(0);				//  调用带参构造函数
    }
    ~Test()
    {
        printf("~Test()\n");
    }
    void print()
    {
        printf("x = %d\n", x);
    }
private:
    int x;
};
int main()
{
    Test t;
    t.print();
    return 0;
}

不带参数的构造函数调用了带参数的构造函数,将 x 初始化为 0。

编译运行:

$ g++ 15-1.cpp -o 15-1
$ ./15-1
~Test()
x = 21928
~Test()

我们可以看到,类的成员变量 x 并没有被初始化为 0,而是随机值。并且调用了两次析构函数。这是为什么呢?

解析:

  • 直接调用构造函数将产生一个临时对象
  • 临时对象的声明周期只有一条语句的时间,作用域在一条语句中

1.2 问题解决

那对于上面的代码,如果初始化工作非常复杂,我们又想实现代码复用,应该怎么办呢?
一般我们会声明一个私有的成员函数完成初始化,让构造函数调用它。

//15-2.cpp
#include<stdio.h>
class Test
{
public:
    Test(int i)
    {
    	init(i);
    }
    Test()
    {
        init(0);
    }
    ~Test()
    {
        printf("~Test()\n");
    }
    void print()
    {
        printf("x = %d\n", x);
    }
private:
    int x;
    void init(int i)
    {
        x = i;
    }
};
int main()
{
    Test t;
    t.print();
    return 0;
}

定义私有初始化函数 init(),然后不同的构造函数调用初始化函数。

$ g++ 15-2.cpp -o 15-2
$ ./15-2
x = 0
~Test()

2 编译器会减少临时对象

  • 现代的 C++ 编译器在不影响最终执行结果的前提下,会尽力减少临时对象的产生

构造函数可能会非常大,减少临时对象可以减少调用构造函数,提高效率。

下面看一示例:

// 15-3.cpp
#include<stdio.h>
class Test
{
public:
    Test(int i) : x(i)
    {
        printf("Test(int):%d\n", i);
    }
    Test() : x(0)
    {
        printf("Test()\n");
    }
    Test(const Test& t)
    {
        x = t.x;
        printf("Test(const Test&:%d\n)", t.x);
    }
    void print()
    {
        printf("x = %d\n", x);
    }
    ~Test()
    {
        printf("~Test()\n");
    }
private:
    int x;
};
Test func()
{
    return Test(20);
}
int main()
{
    Test t = Test(10);
    Test tt = func();
    t.print();
    tt.print();
    return 0;
}

上面的代码很简单,主要是为了说明现代的 C++ 编译器尽力减少临时对象的产生。

第 36 行,直接使用 Test(10) 将产生一个临时对象,再赋值给 t 又会调用拷贝构造函数。
函数 func() 产生一个临时对象并返回,将返回对象赋值给 tt,也将调用拷贝构造函数。

但是,实际上 g++ 编译器经过优化,这里避免了临时对象的产生,也不会调用拷贝构造函数。所以:
第 36 行等价于 Test t = 10;
第 37 行等价于 Test tt = 20;

$ g++ 15-3.cpp -o 15-3
$ ./15-3
Test(int):10
Test(int):20
x = 10
x = 20
~Test()
~Test()

3 小结

1、直接调用构造函数将产生一个临时对象
2、临时对象是性能瓶颈,也是 bug 来源,现在 C++ 编译器会尽力避开临时对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值