C++编译器的RVO和NRVO
1、说明
我一直记得返回对象的函数在调用时会有拷贝构造动作,但是最近实际测试却和记忆有些偏差,经查询是编译的问题
RVO: return value optimization
NRVO: named return value optimization
这两个是编译器的一种函数返回值优化策略
先说结果,VS在debug模式下默认 RVO,release模式下默认 NRVO;而g++在debug和release下都默认NRVO
2、示例
先看一组代码
class Test
{
public:
explicit Test(int num)
: num(num)
{
cout << "constructor " << num << endl;
}
Test(const Test &test)
{
cout << "copy constructor " << test.num << endl;
num = test.num;
}
~Test()
{
cout << "destructor " << num << endl;
}
void print() const
{
cout << "print " << num << endl;
}
private:
int num{};
};
Test getTest(int num)
{
Test test(num);
return test;
}
int main()
{
Test test2 = getTest(12);
test2.print();
return 0;
}
函数 getTest() 返回一个对象,main() 函数中调用并复制给变量理应有一个拷贝构造的动作,但是实际上返回值为
constructor 12
print 12
destructor 12
打印变量地址也发现,getTest() 函数内的变量 test 和 main() 函数中的变量 test 的地址居然是一样的。是我记错了吗?其实不是,根据C++语法,确实应该有拷贝构造的动作,这里的结果是编译器优化的后的,就是上文所说的 RVO 和 NRVO
3、编译器优化
g++ 可以使用参数 -fno-elide-constructors 来关闭优化,CMakeList 使用以下代码关闭
add_compile_options(-fno-elide-constructors)
或者
set(CMAKE_CXX_FLAGS “-fno-elide-constructors ${CMAKE_CXX_FLAGS}”)
如果我们关闭编译器的优化,最后输出的结果应该是
constructor 12 //getTest()函数内构造test对象
copy constructor 12 //getTest()的返回值不能是test对象,需要一个临时变量,使用test对象拷贝构造临时对象_test
destructor 12 //getTest()返回,test对象被析构
copy constructor 12 //main()函数使用test2变量接收临时对象_test
destructor 12 //临时对象_test被析构
print 12 //print()调用
destructor 12 //main()函数内test2对象被析构
不难理解,我的记忆没错,根据C++语法确实应该有拷贝构造,只不过是编译器优化了
C++编译器的RVO和NRVO的更多相关文章
- C++编译器优化技术:RVO、NRVO和复制省略
现代编译器缺省会使用RVO(return value optimization,返回值优化).NRVO(named return value optimization.命名返回值优化)和复制省略(Co ...
- RVO和NRVO
返回值优化(Return Value Optimization,简称RVO),是这么一种优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消耗一个构造函数(C ...
- 第15课 右值引用(2)_std::move和移动语义
1. std::move (1)std::move的原型 template<typename T> typename remove_reference<T>::type& ...
- duang!!!为什么函数能够返回unique_ptr
C++虐我千百遍,我待C++如初恋 从智能指针说起 对高手而言.指针是上天入地的神器.对新手而言,那简直是灾难的源泉.高级语言如Java,C#都自己主动管理内存.你仅仅管new.不必担心内存释放问题. ...
- C++返回值优化
返回值优化(Return Value Optimization,简称RVO)是一种编译器优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用于返回,那么这个临时对象会消耗一个构造函数(C ...
- C++ 11 右值引用以及std::move
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...
- Effective Modern C++:05右值引用、移动语义和完美转发
移动语义使得编译器得以使用成本较低的移动操作,来代替成本较高的复制操作:完美转发使得人们可以撰写接收任意实参的函数模板,并将其转发到目标函数,目标函数会接收到与转发函数所接收到的完全相同的实参.右值引 ...
- copy elison & RVO & NRVO
蓝色的博文 To summarize, RVO is a compiler optimization technique, while std::move is just an rvalue cast ...
- 返回值优化(RVO)
C++的函数中,如果返回值是一个对象,那么理论上它不可避免的会调用对象的构造函数和析构函数,从而导致一定的效率损耗.如下函数所示: A test() { A a; return a; } 在test函 ...
- 【M20】协助完成“返回值优化(RVO)”
1.方法返回对象,会导致临时对象的产生,这降低了效率,const Rational operator* (const Rational& lhs,Rational& rhs).有没有什 ...
随机推荐
- Codeforces Round #687 (Div. 2, based on Technocup 2021 Elimination Round 2) (个人题解)
Codeforces Round #687 (Div. 2, based on Technocup 2021 Elimination Round 2) A. Prison Break https:// ...
- 二、mongo集群搭建
系列导航 一.linux单机版mongo安装(带密码验证) 二.mongo集群搭建 三.java连接mongo数据库 四.java对mongo数据库增删改查操作 五.mongo备份篇 mongoexp ...
- Vue源码编译过程
Vue源码编译过程一.挂载初始化$mounted会挂载组件,不存在 render 函数时需要编译(compile);二.compile1.compile 分为 parse,optimize 和 gen ...
- windows10测试时如何构造大图片(如超过8M+的图片)
1.原图片(大小40k) 2. 选怎一个容量大的文件如视频文件8M+ 3.使用copy命令进行扩容(cmd命令行操作): copy test01.jpg /b + 8M.MP4 test01_8M.j ...
- 简化 libevent 编译
在 CMakePresets.json 的 cacheVariables 字段加入 { "EVENT__DISABLE_OPENSSL": "ON", &quo ...
- kibana上执行ES DSL语言查询数据并查看表结构与数据、删除索引、查看文件大小
转载请注明出处: 1.kibana 上执行DSL 语言: 在kibana 中找到 Dev Tools,并双击打开,就可以进入执行DSL得执行页面了 执行DSL,示例如图: 2.在kibana上查看ES ...
- idea 解决git更新冲突
转载请注明出处: 对使用idea工具解决git冲突,最近有发现不同的解决冲突的方法,都很快捷方便,记录一下. 1.先commit 再pull,然后手动进行merge 左边部分是本地仓库的代码,右边部分 ...
- 【架构师视角系列】Apollo配置中心之Client端(二)
原创文章,转载请标注.https://www.cnblogs.com/boycelee/p/17978027 目录 声明 配置中心系列文章 一.客户端架构 1.Config Service职责 (1) ...
- linux 开机默认进入命令行模式
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
- 30-组合可编程逻辑器件-PLD
组合可编程逻辑器件 1.PLD的结构 1.1 结构 1.2 表示方法 实心点表示连接,但是不可编程 ×点表示连接,但是可以编程 2.编程技术 2.1 熔丝工艺 每个输入线连接二极管和保险丝 2.2 电 ...