C++中返回对象的情形及RVO

之前有文章介绍过临时对象和返回值优化RVO方面的问题。见此处

在C++中,返回对象这一点经常被诟病,因为这个地方的效率比较低,需要进行很多的操作,生成一些临时对象,如果对象比较大的会就会比较耗时。但是在编译器实现的时候,经常是对返回对象的情况进行优化,也就是进行返回值优化

在g++中,这个是默认已经进行了优化。以前我希望看看到底C++怎么操作的,但是无法看到,就是因为G++进行了默认的返回值优化RVO。今天在晚上发现可以有一中方法来禁止这个RVO,可以参考这儿

具体来说就是在编译的时候,加上-fno-elide-constructors这个选项,即:

 

g++ -o rvo_test rvo_test.cc -fno-elide-constructors

下面是一个示例,来演示C++在返回对象的时候所做的优化。

代码如下:

#include <iostream>
#include <iomanip>
using namespace std;
int num=1;
class A{
    public:
        A(){
            id=count++;
            pre_id=-1;
            cout<<setw(2)<<num++<<": A():id="<<id<<" pre_id="<<pre_id<<endl;
        }
        A(const A& a){
            id=count++;
            pre_id=a.id;
            cout<<setw(2)<<num++<<": A(const A&):id="<<id<<" pre_id="<<pre_id<<endl;
        }
        ~A(){
            cout<<setw(2)<<num++<<": ~A():id="<<id<<" pre_id="<<pre_id<<endl;
        }
        A& operator=(const A& a){
            pre_id=a.id;
            cout<<setw(2)<<num++<<": =(const A&):id="<<id<<" pre_id="<<pre_id<<endl;
        }
    private:
        static int count;
        int id;
        int pre_id;
};
int A::count=0;
A f(){
    A a;
    return a;
}
A g1(A b){
    A a=b;
    return a;
}
A g2(A b){
    A a;
    a=b;
    return a;
}
int main(){
    A B1=f();
    A B2=g1(b1);
    A B3=g2(b1);
    A c1,c2,c3;
    c1=f();
    c2=g1(c1);
    c3=g2(c1);    

    return 0;
}

 为了便于区分每一个对象,采用变量id来记录对象的标号。实现方式是采用了一个静态变量count来记录生成类的个数。

下面是运行结果。左边部分是不采用-fno-elide-constructors这个选项,即采用RVO优化的情形,中间是部分测试代码,右边是采用-fno-elide-constructors这个选项,即不采用RVO的情形,所以右边是我们需要看的,需要分析的类的真正的执行过程。同时为了便于标示比较,对运行的每一行进行了标号: