目录
大纲
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会先发生构造匿名对象然后再拷贝构造到形参对象。
优化后:变为一次拷贝构造
返回时。
第一行的不用管。
这里的析构函数调用时形参的原因不用管。
我们看原本:des返回后先拷贝构造到临时空间(匿名对象)然后正在拷贝构造到copy中。
优化后:变为一次拷贝构造
在同行或函数调用传参时与函数返回的返回传值时,我们的编译器会对多次构造拷贝等等,优化为一次构造函数。
4.匿名使用场景以及注意事项;
第3点说明了同行或函数调用传参时与函数返回的返回传值,类多次实例化,编译器会优化为一次,那么如果不是同一行的构造,编译器会优化吗?
这里我们先声明copy,然后通过运算符重载,看看编译器会不会优化处理
编译器未没有优化处理。发生:默认构造+传参构造+运算符重载+析构函数=为了一次copy的值
我们继续F10。
原本这一行会发生=匿名构造+_copy拷贝构造+匿名析构,编译器会优化为一次_copy的构造;
发现仅仅只发生了一次传参构造,使用'C'传参构造_copy对象。
说明:copy对象与_copy对象的工作其实是一样的都是将字符‘c’传入到对象中,而copy的工作调用了4个函数,而_copy仅仅调用一次构造函数,就完成了工作,大大提升了效率。这是我们所追求的。
结论:当我们初始化时应该直接就赋值,这可大大提高程序效率。
5.匿名对象生命周期的延迟;
匿名数据难道只能即用即销毁吗?非也。
我们可以利用引用延迟他的死亡。由于匿名对象具有常性,引用类型必须加const。
根据前面内容,F10后我们会创建匿名对象后立刻销毁。但是引用后会强行续命
在下一行后,不会调用析构函数回收匿名对象资源。
在函数结束后才会销毁创建的对象。
其实这里我们可以认为我们匿名对象变为了rt引用名,rt就是该空间唯一名字。
谢谢你的阅读谢谢!!