编译器Return value optimization(RVO)时机以及基本原理

直接讲结论,在gcc 10.2下,关闭优化-O0的情况下,编译器同样会启用RVONRVO
。然而,再通过-fno-elide-constructors禁用RVO之后,编译器如果发现存在移动构造函数,会优先使用移动构造而不是拷贝构造。

cmake_minimum_required(VERSION 3.24)

project(rvo_testing)

add_executable(
    exec_with_fno_elide
    main.cpp
)
set_target_properties(exec_with_fno_elide 
    PROPERTIES 
    COMPILE_FLAGS 
    "-fno-elide-constructors -O0"
)

add_executable(
    exec_default
    main.cpp
)
set_target_properties(exec_default 
    PROPERTIES 
    COMPILE_FLAGS 
    "-O0"
)
#include <iostream>

using namespace std;
// static const char __func__[] = "function-name";

class Foo{
  public:
    Foo(){
        // gnu c extension
        cout << __PRETTY_FUNCTION__ << endl;
    }
    Foo(const Foo&){
        cout << __PRETTY_FUNCTION__ << endl;
    }
    Foo(const Foo&&){
        cout << __PRETTY_FUNCTION__ << endl;
    }
    ~Foo(){
        cout << __PRETTY_FUNCTION__ << endl;
    }

};

// NRVO
Foo ReturnLocalObjWithNamed(){
    Foo foo;
    return foo;
}

// RVO
Foo ReturnLocalObjWithAnon(){
    // Foo foo;
    return Foo();
}

// without RVO
Foo ReturnLocalObjWithMove(){
    // Foo foo;
    return std::move(Foo());
}

int main(){
    // buf ==> convert to Foo pointer
    {
        Foo obj = ReturnLocalObjWithNamed();
    }
    cout << "===============" << endl;
    {
        Foo obj = ReturnLocalObjWithAnon();
    }
    cout << "===============" << endl;
    {
        Foo obj = ReturnLocalObjWithMove();
    }
    
    return 0;
}

底层原理

本质上相当于,在main函数之前分配一块内存存放Foo对象,传递对象指针给调用函数。
同时在调用函数内部使用placement new 初始化Foo对象

ReturnLocalObjWithNamed():
 push   rbp
 mov    rbp,rsp
 sub    rsp,0x10
 mov    QWORD PTR [rbp-0x8],rdi // 64位系统下, 指针占用 8bytes
 mov    rax,QWORD PTR [rbp-0x8]
 mov    rdi,rax
 call   401320 <Foo::Foo()>     // Foo构造函数
 nop
 mov    rax,QWORD PTR [rbp-0x8]
 leave  
 ret    

这个是main函数调用的ReturnLocalObjWithNamed的汇编代码

 push   rbp
 mov    rbp,rsp
 sub    rsp,0x10       // 栈上分配0x10字节
 lea    rax,[rbp-0x1]  // 注意Foo是空类, 这里描述的是分配了一个Foo对象
 mov    rdi,rax        // rdi: Foo对象指针
 call   401196 <ReturnLocalObjWithNamed()>
 lea    rax,[rbp-0x1]
 mov    rdi,rax
 call   40137c <Foo::~Foo()>

相当于直接在main函数那里,分配内存,在ReturnLocalObjWithNamed中进行初始化…

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值