自己动手理解NRV优化

来源:互联网 发布:广数g72编程实例讲解 编辑:程序博客网 时间:2024/05/17 02:33

自己动手理解NRV优化

2010.6.29

一、NRV的简单理解

    NRV是Named Return Value的简称。NRV优化简单的说:有一条语句,A a = f();其中f()是一个函数,函数里边申请了一个A的对象b,然后把对象b返回。在对象返回的时候,一般情况下要调用拷贝函数,把函数f()里边的局部对象b拷贝到函数外部的对象a。但是如果用了NRV优化,那就不必要调用拷贝构造函数,编译器可以这样做,把a的地址传递进函数f(),然后不让f()申请要返回的对象b的空间,用a的地址来代替b的地址,这样当要返回对象b的时候,就不必要拷贝了,因为b就是a,省去了局部变量b,省去了拷贝的过程。

二、动手测试

    书上得来终觉浅。动手测试才是王道。

测试代码如下:

测试环境:32位机器,vs2005编译器。

测试部分截图

图 1 debug模式下main()函数

 

图 2 debug模式下f()函数

 

图 3 release模式下 main()函数

 

图 4 release模式下f()函数

三、分析

     (1)debug模式

分析图 1和图 2可以发现在调用f()函数时,传进了一个参数,这个参数就是拷贝构造函数的目标对象。而拷贝构造函数的源对象就是在f()函数里边定义的局部对象。

     (2)release模式

分析图 3和图 4可以发现在调用f()函数时,通过esi传递了外部对象b的地址,在f()函数里边没有申请局部对象的空间,没调用构造函数(内联了),只是输出"construct",也没调用strcpy函数,而是通过寄存器把"zhangsan"拷贝到esi所指向的地址。release模式做了很大的优化!

    

      (3)总结

     可以这样理解:debug模式下,给函数传递外部变量b的地址,函数内先申请一个局部变量a,接着对a操作,最后调用拷贝构造函数把a拷贝到外部变量b,结束返回。release模式下,给函数传递外部变量b的地址,函数内不申请局部变量a的空间,把b作为a的空间,接着对a操作,结束返回。

    release模式下,局部变量构造函数的操作还是有的,就是没有申请空间,通过寄存器拷贝字符串"zhangsan"的过程就是在调用构造函数,不过看起来被内联在f()函数里边了。可以在f()函数返回之前,局部变量定义之后增加几行代码,再进行测试。

 

四、关于测试

    1、 如何测试?为了方便测试可以输出一些字符,然后在OD里使用超级字符串查找插件,方便定位。

    2、如何知道有没有申请空间?看函数入口处有没有类似于sub esp,XX的指令,在debug模式下会发现f()函数里边有申请局部变量,而release模式下f()函数没有申请局部变量。

    3、一般情况下,堆栈的局部变量会采用[ebp-XX]的方式访问,而通过堆栈传递的参数会采用[ebp+XX]的方式访问。另外要注意在函数采用寄存器传递参数,例如:this指针采用ecx寄存器,esi作为外部变量的地址。

 

 

相关问题:http://topic.csdn.net/u/20100628/20/d4f1c6bf-69fc-4b7e-b2b6-09a3a46d1ba7.html?seed=808337921&r=66584952#r_66584952

 

PS:有不对之处请指正。

 

原创粉丝点击