匿名对象以及临时空间

目录

大纲

1.何为匿名对象

2.产生匿名对象的四种情况:

1)给初始化对象时

2)以值的方式给函数传参;

3)类型转换;

4)函数返回时;

3.编译器优化

I.在同一行代码的优化

II.在函数调用和返回时。

4.匿名使用场景以及注意事项;


大纲

1.何为匿名对象

2.产生匿名对象的四种情况:                                                                   

3.编译器优化

4.匿名使用场景以及注意事项;

5.匿名对象生命周期的延迟;

以下是测试代码:

class ClTest
{
public:
	ClTest()
		:_flag('K')
	{
		printf("%c:默认构造函数调用:this:%p\n",_flag,this);
	}
	ClTest(const char& tmp)
		:_flag(tmp)
	{
		printf("%c:传参构造函数调用:this:%p\n", _flag, this);
	}
	~ClTest()
	{
		printf("%c:析构函数调用:this:%p\n", _flag, this);
	}
	ClTest(ClTest&e)
	{
		printf("%c:拷贝构造函数调用:this:%p\n", _flag, this);
	}
	ClTest& operator =(const ClTest&)
	{
		printf("%c:赋值运算符重载调用:this:%p\n", _flag, this);
	}
private:
	char _flag;
};

1.何为匿名对象

匿名对象可以理解为是一个临时对象,一般系统自动生成的。这个对象没有名字,通常即用即销毁,在同一行内生成后销毁。

具名==显示

下面是通常即用即销毁演示:调试到41行

 按下F10调试到42行

发现我们构造的匿名对象立刻又销毁了。所以通常情况下,匿名函数都是即用即销毁的。

2.产生匿名对象的四种情况:

1)给初始化对象时

首先:先生成匿名对象,然后使用匿名对象数据拷贝构造copy对象。

2)以值的方式给函数传参;

        这里有个知识点匿名对象是具有常性的,所以在匿名对象传参构造函数时必须加const

这样是掉不动的需要形参加上const 

ps:其实内置类型也可以匿名传参(也是具有常性,但是内置类型通常传值传参足够了)

 我们不写形参名字是允许的,我们不使用形参也就不需要写形参名。

  这里还有个注意点函数调用传参允许创建匿名实参传参,但是不允许创建具名实参传参

 这样是不允许的。

  3)类型转换;

 其实他可以等价为

I、II、III的的工作其实是一样的,都是利用一个对象拷贝构造另一个对象,只是I和II利用匿名对象而III是创建具名对象,然后利用具名对象拷贝构造copy对象。

4)函数返回时;

1.返回类型为传值返回,拷贝构造接收。

 首先我们知道临时空间与匿名对象都是常性数据,但是传值接收到ret是被允许的

2.返回类型为传值返回,引用接收。

我们必须要加const

 注意!!!这里的返回值其实发生了野引用,引用了临时空间的数据,他是即用即销毁的,所以尽量不要这样引用

3.返回类型为引用返回,拷贝构造接收。

 注意!!!这里也发生了野引用的出现,当栈销毁时我们引用的des对象被销毁,而临时空间引用了des的数据。但是一般情况下,返回到构造完ret对象后该空间将不在使用了

但是最怕最怕出现ret为引用接收

4.返回类型为引用返回,引用接收。

ret将引用一个被销毁的空间,使用ret极大困难会导致程序崩溃!!!

怎么办呢?我们如果引用在栈中生成的数据?
一、static

 二、堆上数据


3.编译器优化

I.在同一行代码的优化

使用匿名对象时拷贝另一个具名对象

 原本这一行会发生=匿名构造+copy拷贝构造+匿名析构,编译器会优化为一次copy的构造;

编译器会将一行多次重复的动作,改变为只一次拷贝构造。

II.在函数调用和返回时。

调用时

发现原本时调用func会先发生构造匿名对象然后再拷贝构造到形参对象。 

优化后:变为一次拷贝构造

返回时。

思考汇编查看:临时数据返回先到寄存器中然后销栈,寄存器到上层函数的接收处,如无接收就放在寄存器中,下次使用该寄存器将覆盖数据。1-2次拷贝

第一行的不用管。

 这里的析构函数调用时形参的原因不用管。

我们看原本:des返回后先拷贝构造到临时空间(匿名对象)然后正在拷贝构造到copy中。

优化后:变为一次拷贝构造

在同行或函数调用传参时与函数返回的返回传值时,我们的编译器会对多次构造拷贝等等,优化为一次构造函数。


4.匿名使用场景以及注意事项;

第3点说明了同行或函数调用传参时与函数返回的返回传值,类多次实例化,编译器会优化为一次,那么如果不是同一行的构造,编译器会优化吗?

 这里我们先声明copy,然后通过运算符重载,看看编译器会不会优化处理

编译器未没有优化处理。发生:默认构造+传参构造+运算符重载+析构函数=为了一次copy的值

我们继续F10。 

原本这一行会发生=匿名构造+_copy拷贝构造+匿名析构,编译器会优化为一次_copy的构造;

发现仅仅只发生了一次传参构造,使用'C'传参构造_copy对象。

说明:copy对象与_copy对象的工作其实是一样的都是将字符‘c’传入到对象中,而copy的工作调用了4个函数,而_copy仅仅调用一次构造函数,就完成了工作,大大提升了效率。这是我们所追求的。

结论:当我们初始化时应该直接就赋值,这可大大提高程序效率。

5.匿名对象生命周期的延迟;

匿名数据难道只能即用即销毁吗?非也。

我们可以利用引用延迟他的死亡。由于匿名对象具有常性,引用类型必须加const。

 根据前面内容,F10后我们会创建匿名对象后立刻销毁。但是引用后会强行续命

在下一行后,不会调用析构函数回收匿名对象资源。

在函数结束后才会销毁创建的对象。

其实这里我们可以认为我们匿名对象变为了rt引用名,rt就是该空间唯一名字。


谢谢你的阅读谢谢!!

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云的小站

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

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

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

打赏作者

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

抵扣说明:

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

余额充值