关于类型对象作为形参和返回值时的一些问题

首先,函数形参和返回值如果在不使用引用的情况下是按照所谓传值(by-value)的方式来进行传递的。其本质是由编译器产生临时对象,将实参或者返回值拷贝给临时对象,之后的操作都是在临时对象上进行,当函数结束的时候再释放掉临时对象。

那么,当我们面对类类型对象作为形参和返回值时,其构造函数及析构函数是如何运作的呢?下面通过一系列代码来进行追踪:

通过这个程序可以看到,我在主函数中定义了一个对象,在foo函数中也定义了一个局部对象,那么总共会发生几次构造几次析构呢?答案在这里:

可以看到,在程序中总共存在着两次构造函数和两次拷贝构造函数,但是只有三次析构函数。也就是说,存在一个对象没有被析构,这是为什么呢?下面通过对foo函数的伪代码展开来进行分析。

Foo()的C++伪代码:

//第一次构造

xx.XX::XX();                                      

XX  _temp0;                                                                                       

//第一次拷贝

_temp0.XX::XX(xx);                                                                      

void foo(XX&_result, _temp0)

{

  //第二次构造

yy.XX::XX();                                                                              

//赋值

yy.operator=(_temp0);                                                                

   //第二次拷贝

_result.XX::XX(yy);                                                      

return;

}

  //第一次析构

yy.XX::~XX();

  //第二次析构                                                                         

_result.XX::~XX();               

  //第三次析构                                                           

_temp0.XX::~XX();                                                                         

 

可以看出,main()函数中的对象xx并不参与析构,可以理解为对象xx将于整个程序结束后方由编译器析构释放。此时,无法在控制台中追踪析构情况。

 

接下来讨论一个变种情况,主函数代码修改如下:

可以看到,此时我在主函数中又申请了一个XX类型的对象t用来保存foo函数的返回值,这次运行又会发生什么事呢?

可以看到,析构函数的调用又少了一次!!

再次对foo函数进行展开分析:

Foo()的C++伪代码:

  //第一次构造

xx.XX::XX();                                       

XX  _temp0; 

//第一次拷贝                                                                                    

_temp0.XX::XX(xx);                                                                         

XX t;

void foo(&t,_temp0)

{

  //第二次构造

        yy.XX::XX();

  //赋值                                                                   

        yy.operator=(_temp0);  

//第二次拷贝                                   

        t.XX::XX(yy);                                                                    

return;

}

//第一次析构

yy.XX::~XX();    

  //第二次析构                                                                                

_temp0.XX::~XX();                                                                            

 

可以看到,由于主函数中的对象t取代了临时对象_result,所以导致对_result的析构调用不存在了,而t本身是main函数中的对象,所以和xx一样在main函数结束的时候才会被析构调用,故无法追踪。

 

在对象作为返回值时,存在一种称为NRV的优化措施,该措施对于上面的代码展开的影响如下:

Foo()的C++伪代码:

  //第一次构造

xx.XX::XX();                                        

XX  _temp0;    

//第一次拷贝                                                                                   

_temp0.XX::XX(xx);                                                                           

XX t;

void foo(&t,_temp0)

{

  //第二次构造

         t.XX::XX();           

  //赋值                                                         

         t.operator=(_temp0);                                                            

return;

}

  //第一次析构

_temp0.XX::~XX();                                                                            

 

可以看到,在开启NRV优化的情况下,局部对象yy将被临时对象_result或是用来保存返回值的对象t所替代,所以对于对象yy的析构调用也不存在了,所以只会有一次析构调用。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值