C++中的RVO优化,针对返回值为对象时临时对象的优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TK_lTlei/article/details/84404125

摘要:
RVO (return value optimization) 和NRVO (named return value optimization) 是C++在处理一个函数返回类对象并将返回值赋给另一个对象时,为了减少拷贝构造次数以及析构次数而采用的一种编译器优化技术。
当函数的返回值为对象时,内部的调用是如何的,下面看例子:

#include <iostream>
using namespace std;
class Byte
{
        private: int  b;
        public:
                Byte(int bb=0):b(bb){
                cout<<"constructor,address:"<<this<<endl;
                }
                Byte(const Byte& byte){
                b=byte.b;
                cout<<"copy constructor,address:"<<this<<endl;
                }
                const Byte operator++(int)
                {   Byte before(b);
                    b++;
                    return before;

                }
                int  getcr()
                {
                     return b;
                }
                ~Byte(){
                cout<<"deconstructor,address:"<<this<<endl;
                }
};

int main()
{
        Byte tmp(10);
        const Byte tmp2=tmp++;                   //用一个对象来接受这个临时对象
        //const Byte* tmp2=&(tmp++);
        cout<<tmp2.getcr()<<endl;
        cout<<"compiler end"<<endl;
}

执行结果(g++加参数-fno-elide-constructors,去掉rvo优化):

constructor,address:0x7ffdb92f9a10               //tmp(10)    函数构造
constructor,address:0x7ffdb92f99e0               //构造before(b)
copy constructor,address:0x7ffdb92f9a30          //拷贝构造到临时对象
deconstructor,address:0x7ffdb92f99e0             //before调用析构函数
copy constructor,address:0x7ffdb92f9a20          //拷贝构造函数,从临时对象拷贝到tmp2
deconstructor,address:0x7ffdb92f9a30             //临时对象调用析构函数
10                                               //tmp.b的值为10
compiler end                                 
deconstructor,address:0x7ffdb92f9a20             //程序结束,释放tmp2
deconstructor,address:0x7ffdb92f9a10             //程序结束,释放tmp

去掉-fno-elide-constructors,rvo优化,结果:

constructor,address:0x7ffca1a17170                //tmp构造函数
constructor,address:0x7ffca1a17180                //tmp2构造函数
10
compiler end
deconstructor,address:0x7ffca1a17180              //tmp析构函数
deconstructor,address:0x7ffca1a17170              //tmp2析构函数

接下来,将函数改为:

int main()
{
        Byte tmp(10);
        //const Byte tmp2=tmp++;                  
        const Byte* tmp2=&(tmp++);                               //用指针指向临时对象的地址
        cout<<tmp2.getcr()<<endl;
        cout<<"compiler end"<<endl;
}

程序运行结果:

constructor,address:0x7ffc4f9a3420                //tmp(10)    函数构造
constructor,address:0x7ffc4f9a33f0                //构造before(b)
copy constructor,address:0x7ffc4f9a3430           //拷贝构造到临时对象
deconstructor,address:0x7ffc4f9a33f0              //before调用析构函数
deconstructor,address:0x7ffc4f9a3430              //临时对象调用析构函数
10                                                //临时对象地址已经被释放(此处为何仍能输出10,此处留下一个疑问)
compiler end
deconstructor,address:0x7ffc4f9a3420              //程序结束,释放tmp

去掉-fno-elide-constructors,rvo优化,结果:

constructor,address:0x7ffedc840340                   //tmp构造函数
constructor,address:0x7ffedc840350                   //临时对象构造函数
deconstructor,address:0x7ffedc840350                 //临时对象析构函数(为什么临时对象都释放掉了,还能调用函数得到b的值?)
10
compiler end
deconstructor,address:0x7ffedc840340                 //tmp析构函数

此时,我本文的目的就达到了,就是返回的对象是一个临时对象,这个函数执行完之后,就会释放,其他还有各种函数返回值优化的验证模型,比如将return Byte(b++)会是什么结果?编译器是如何对这些语句进行优化的?NRVO是如何优化的?这些都可以在《在深度探索C++对象模型》中得到答案,我本文的目的已经达到,就不在深究了,大家如果感兴趣的话可以在深入研究下。

猜你喜欢

转载自blog.csdn.net/TK_lTlei/article/details/84404125
今日推荐