c++返回值优化的问题

本文总结以下我对返回值优化的学习,主要参考了下面这个链接的学习内容。
[C++中的返回值优化(RVO)]

命名返回值优化(NRVO)

二话不说,先上代码:

#include <iostream>

class A{
public:
    A(){ std::cout << "Default constructor is called." << std::endl; }
    A( const A& rhs ){ std::cout << "Copy constructor is called." << std::endl; }
    A& operator=( const A& rhs ){
        std::cout << "operator=() is called." << std::endl;
        return *this;
    }
    ~A(){ std::cout << "Destructor is called." << std::endl; }

};

A foo(){
    std::cout << "******foo is entered!********" << std::endl;
    A a;
    std::cout << "******foo is leaved!*********" << std::endl;
    return a;
}

int main( void ){

    A b;
    b = foo();

    return 0;
}

首先先讨论未优化的情形
编译时加入-fno-elide-constructors 选项,禁止NRVO。
g++ -g -fno-elide-constructors -o main main.cpp

-fno-elide-constructors
The C++ standard allows an implementation to omit creating a
temporary which is only used to initialize another object of the
same type. Specifying this option disables that optimization, and
forces G++ to call the copy constructor in all cases.

/*未优化结果
Default constructor is called. // b的构造函数
******foo is entered!********  
Default constructor is called. // a的构造函数
******foo is leaved!*********
Copy constructor is called. // 通过a调用拷贝构造,生成临时对象
Destructor is called. // a析构
operator=() is called.// 临时对象完成对b的赋值
Destructor is called. // 临时对象析构
Destructor is called. // b析构
/*

从未优化的结果来看,如果返回一个对象的情形,在未优化时会用这个命名对象调用拷贝构造生成一个临时对象,然后命名对象析构,临时对象再调用赋值函数进行赋值,临时对象再析构。

返回值不优化时,会生成临时对象。

下面讨论返回值优化的情形
从上面的分析我们应该可以猜到,返回值如果优化,会避免生成临时对象,可以用命名对象直接对左值进行赋值。

/*
Default constructor is called. // b的构造函数
******foo is entered!********
Default constructor is called. // a的构造函数
******foo is leaved!*********
operator=() is called. // 命名对象a直接对b进行赋值
Destructor is called. // a析构
Destructor is called. // b析构
*/

果然,避免了临时对象的生成。

再看一段代码,这段代码主要是为了测试直接进行构造的情形:

#include <iostream>

class A{
public:
    A(){ std::cout << "Default constructor is called." << std::endl; }
    A( const A& rhs ){ std::cout << "Copy constructor is called." << std::endl; }
    A& operator=( const A& rhs ){
        std::cout << "operator=() is called." << std::endl;
        return *this;
    }
    ~A(){ std::cout << "Destructor is called." << std::endl; }
};

A foo(){
    std::cout << "******foo is entered!********" << std::endl;
    A a;
    std::cout << "******foo is leaved!*********" << std::endl;
    return a;
}

int main( void ){

    A b = foo();

    return 0;
}

直接给结果:

/*
******foo is entered!********
Default constructor is called. // 构造对象a
******foo is leaved!*********
Copy constructor is called. // 通过对象a构造临时对象
Destructor is called. // 对象a析构
Copy constructor is called. // 临时对象拷贝构造b
Destructor is called. // 临时对象析构
Destructor is called. // b析构
*/

下面我们开启优化选项,可以想得到是,应该避免了临时对象的生成。这样就会直接用a去拷贝构造b,然后a析构。

/*
******foo is entered!********
Default constructor is called. // 构造a
******foo is leaved!*********
Destructor is called. // 析构b

*/

发现没有出现我们希望看到的情形,并不是说我们的考虑不到位,而是它优化的太厉害了,连拷贝构造都没有,对于这种优化情形的解释咱是不清楚,先记住这种情形。

未命名返回值优化

先上代码

#include <iostream>

class A{
public:
    A(){ std::cout << "Default constructor is called." << std::endl; }
    A( const A& rhs ){ std::cout << "Copy constructor is called." << std::endl; }
    A& operator=( const A& rhs ){
        std::cout << "operator=() is called." << std::endl;
        return *this;
    }
    ~A(){ std::cout << "Destructor is called." << std::endl; }
};

A foo(){
    std::cout << "******foo is entered!********" << std::endl;
    std::cout << "******foo is leaved!*********" << std::endl;
    return A();
}

int main( void ){

    A b;
    b = foo();
    return 0;
}

/*
Default constructor is called. //生成b对象
******foo is entered!********
******foo is leaved!*********
Default constructor is called. //生成返回对象
Copy constructor is called. // 用返回对象调用拷贝构造生成临时对象
Destructor is called.// 返回对象析构
operator=() is called. // 临时对象对b进行赋值
Destructor is called. // 临时对象析构
Destructor is called. // 对象b析构
*/

上面的结果是没有开编译优化时的情形,这点和之前是一样的,虽然没有显示的生成第一部分讨论的对象a,但是还是生成了一个返回对象。然后用这个返回对象又去生成了临时对象。

下面我们开启优化选项,这样就可以避免临时对象的生成。

/*
Default constructor is called. // 生成对象b
******foo is entered!********
******foo is leaved!*********
Default constructor is called.// 生成返回对象
operator=() is called. // 用返回对象完成赋值
Destructor is called. // 返回对象析构
Destructor is called. // 对象b析构
*/
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值