RVO: Return Value Optimization
NRVO: Named Return Value Optimization

RVO 和 NRVO 自C++98时代就已存在,即当函数按值返回的时候,编译器所做的优化,并不是C++标准所规定的内容,因此各家编译器实现可能有差别,另外当函数比较复杂的时候,也可能不会有RVO或NRVO的优化。

Copy Elision 是 C++11 新增移动语义后给出的一种建议,即当返回值时使用移动语义替代拷贝语义以减少内存拷贝;它属于标准的建议,因此编译器是否实现了该优化以及如何实现仍未可确定(其实一般都实现了)。

1. RVO

T f() {...return T(constructor_arguments);
}T t = f();

理论上,以上代码会创建3个T类的对象:

  1. 在函数 f() 内的这句return语句中,会创建一个无名的对象
  2. 当从f()返回时,会将1中的无名对象进行一次拷贝构造,从而形成一个临时的T类对象
  3. 在 T t = f(); 这一句中,将2中的临时对象通过拷贝构造传给t

但实际上,创建一个T类对象就应该能够搞定一切,这就是 RVO 做的 - 通过直接用构造参数构造t从而减少2次临时构造。

另外,当有多个return语句时,只要所返回的object是在return语句上创建的,那么RVO一般也还是起作用的。如下代码:

T f() {if (....) {return T(....);}else {return T(....);}
}

2. NRVO

顾名思义,NRVO就是所返回的对象是有名字的,也就是说,所返回对象不是在return语句上创建的。代码如下:

T f() {T result(....);....return result;
}

但是注意,与RVO类似,NRVO时函数必须返回一个 unique 的对象,这样编译器才能直到在函数f()的外面应该去构造f()中的哪一个object.
如下代码就是NRVO可以起作用的一种示例:

T f() {T result(....);if (....) {return result;}....return result;
}

综上所述,虽然基本上所有流行的编译器都实现了RVO/NRVO优化,但因为编译器也可能因为做其他优化而放弃了RVO/NRVO,又或者是函数过于复杂而没有做RVO/NRVO,此时,通过引用型参数来传递结果仍不失为一个更通用更符合C++标准的选择。

3. 如何显示去掉 RVO 与 NRVO 优化

RVO 与 NRVO 优化并不需要额外使用 -O1 或 -O2 或 -O3之类的编译选项也会有。
要去掉 RVO/NRVO 优化,就要显式地使用 -fno-elide-constructors选项。

4. Copy Elision (复制消除)

在 C++11 中,若函数按值返回,则会自动尝试使用move语义,而不是优先使用拷贝语义,这就是 copy elision.

看一段代码:

#include <iostream>
#include <vector>
using namespace std;
vector<int> foo(int n) {vector<int> v;for (int i = 1; i <= n; i++) {v.push_back(i);}cout << "address of vector v: "<< &v << " in foo" <<endl;cout << "vector v.data(): "<< v.data() << " in foo" <<endl;return v;
}int main() {vector<int> v = foo(10);cout << "address of vector v: "<< &v << " in main" <<endl;cout << "vector v.data(): "<< v.data() << " in main" <<endl;
}

编译命令为:

g++ 2.cpp -std=c++03 -fno-elide-constructors -o 03.out
g++ 2.cpp -std=c++11 -fno-elide-constructors -o 11.out

执行结果为:

$ ./03.out
address of vector v: 0xffffcb80 in foo
vector v.data(): 0x800012910 in foo
address of vector v: 0xffffcbe0 in main
vector v.data(): 0x800012990 in main$ ./11.out
address of vector v: 0xffffcb80 in foo
vector v.data(): 0x800012910 in foo
address of vector v: 0xffffcbe0 in main
vector v.data(): 0x800012910 in main

由上可见,
去除RVO/NRVO优化后,对C++03的程序,v.data() 在 foo 中和 main 中都不一样了,即拷贝发生了;
但是对C++11的程序,虽然vector v的地址确实变化了(在foo中和在main中不同了),但其内容并没有经过拷贝,main中的v仍然用的是foo中的v的内存。

但是话说回来,如果是自己定义的类,并且没有定义移动构造函数,则函数按值返回的时候,还是会发生内存拷贝的;
而自定义的类若有移动构造函数,则函数按值返回也会应用到移动语义,从而减少内存拷贝。

(完)

C++中的RVO、NRVO与Copy Elision相关推荐

  1. 浅谈C++11标准中的复制省略(copy elision,也叫RVO返回值优化)

    严正声明:本文系作者davidhopper原创,未经许可,不得转载. C++11以及之后的C++14.17标准均提出一项编译优化技术:复制省略(copy elision,也称复制消除),另外还有RVO ...

  2. C++17之省略不必要的拷贝Copy Elision

    从C++发展历史看来,c++ 17引入了一个规则,要求在满足一定的条件下避免对象的复制,这在以前是可选的.C++17中一个叫做强制复制省略的技术就是基于这个观点的. 至少包括以下两项内容: 1. 返回 ...

  3. 一道面试题:你了解哪些编译器优化行为?知道Copy elision 、RVO吗?

    C++11以后,g++ 编译器默认开启复制省略(copy elision)选项,可以在以值语义传递对象时避免触发复制.移动构造函数.copy elision 主要发生在两个场景: 函数返回的是值语义时 ...

  4. C++编程法则365条一天一条(358)copy elision(返回值优化NVO和具名返回值优化NRVO)

    文章目录 强制编译器实现的优化 非强制实现优化 参考:https://en.cppreference.com/w/cpp/language/copy_elision Elision 是省略.删节或者忽 ...

  5. copy elison RVO NRVO

    蓝色的博文 To summarize, RVO is a compiler optimization technique, while std::move is just an rvalue cast ...

  6. C++中的RVO和NRVO

    RVO (return value optimization) 和NRVO (named return value optimization) 是C++在处理 "返回一个class obje ...

  7. Intro to Copy Elision and (N)RVO

    不写了,这个东西越研究就越多,滚雪球一样,暂时撤退.. 感觉现在C++水平也算是勉强入门了,不再是C with STL了(逃). 不过很多东西诸如compiling, parsing, linking ...

  8. c++的复制省略(copy elision)

    学习 A simple C++11 Thread Pool 时,发现函数返回了std::future,而std::future的拷贝构造和拷贝赋值都是delete的,感觉有点怪,查了一下,看到 编译器 ...

  9. 有保证的复制消除(Guaranteed Copy Elision)

    作者:Jonas Devlieghere 原文地址:https://jonasdevlieghere.com/guaranteed-copy-elision/ 新的 C++ 17 标准带来了很多令人兴 ...

最新文章

  1. 判断是否移动端设备的JS代码,超短,百度都用它
  2. 二叉查找树--java
  3. 无线端不响应键盘事件(keydown,keypress,keyup)
  4. 获得最新纪录 sql
  5. 【并查集】【图论】【最小生成树】剑鱼行动(ssl 1618)
  6. 大数据开发工具hive内部常用函数都有哪些?
  7. Liferay Portlet 结构分解
  8. freepiano 手残党也想弹钢琴(在电脑上弹奏电子钢琴自娱自乐,也许还是有点困难,不如试试freepiano+鼠标宏,这样用简谱就不怕残疾了)
  9. 安科瑞电力监控系统在安徽华光有效薄膜太阳能电池高温玻璃项目的应用
  10. AE渲染加快速度,解决导出视频太慢的问题
  11. 用python解决放苹果问题_分苹果问题的C++和Python实现
  12. python雪花下落代码_雪花算法python实现
  13. 类Loopy是公共的, 应在名为 Loopy.java 的文件中声明
  14. 跌吧,继续跌吧,小灰的基金已亏损64万。。。
  15. acwing 846. 树的重心
  16. SQL Server “链接服务器”的使用
  17. 达内培训python视频教程
  18. 永久免费开源在线客服系统推荐收藏
  19. 运维 - 第一阶段 - linux与shell编程
  20. 马蜂窝助力智慧旅游新发展,借助大数据重构传统旅游产业链

热门文章

  1. uniapp 自制头部左侧胶囊组件
  2. c语言编程中的或逻辑的符号 符号如何输入,C语言中逻辑运算符(,||,!)和位运算符号(,|,^)...
  3. 解决Android studio 模拟器闪烁黑屏问题
  4. WinSCP(版本5.7.6)中文文件名显示乱码
  5. zcmu-1931 wjw的剪纸
  6. prometheus-community-PushProx介绍
  7. ESP32-C3入门教程 基础篇(六、TIMG 硬件定时器 与 软件定时器)
  8. 百度“文心一言”首批生态合作伙伴公布,Moka接入打造人力资源数字化人AI服务
  9. 2020搞一个副业项目需要什么技能?
  10. adb常用命令以及使用