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 #712 (Div. 2) 个人题解
这一场打的又很差(掉分预定),D题想不出来. A. Déjà Vu 这题首先判断字符串是否全由 a 组成,如果是的话输出 NO int main() { ios_base::sync_with_std ...
- vue学习笔记 五、创建子组件实例
系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...
- 前端开发环境搭建踩坑笔记——npm install node-sass安装失败的解决方案
.markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...
- AMBA总线介绍-02
AMBA总线介绍 1 HSIZE AHB总线的地址位宽和数据位宽一般都是32bit,一个字节8bit,一个字节占用一个地址空间,但当一个32bit的数据写入一个存储器中或者从一个存储器中读取,32bi ...
- 基于AHB_BUS的eFlash控制器的微架构设计
eFlash微架构设计 1.回顾架构设计 2.Flash时序仿真 2.1 ahb_flashc项目目录 docs rtl sim tb model 2.2 docs 架构设计文档 微架构设计文档 集成 ...
- [转帖]Nginx access log 按日期保存记录
https://cloud.tencent.com/developer/article/1958304 $time_iso8601 生成格式:2021-09-18T15:16:35+08:00 ...
- cri-docker的学习和了解-番外
cri-docker的学习和了解-番外 前言 因为已经有足足两年多没再详细接触K8S了. 然后利用两个晚上搭建了IPV6 SingleStack的K8S单机版 中间一直使用的docker的方式学习和工 ...
- [转帖]TiDB损坏多副本之有损恢复处理方法
https://tidb.net/blog/b1ae4ee7 TiDB分布式数据库采用多副本机制,数据副本通过 Multi-Raft 协议同步事务日志,确保数据强一致性且少数副本发生故障时不影响数 ...
- [转帖]TiDB Lightning 在数据迁移中的应用与错误处理实践
TiDB Lightning 在数据迁移中的应用与错误处理实践 作者简介:DBA,会点 MySQL,懂点 TiDB,Python. 个人主页:https://tidb.net/u/seiang/ans ...
- [转帖]一、Kafka Tool使用
一.Kafka Tool使用 1.添加cluster 2.开启SASL_PLAINTEXT 如果kafka 开启SASL_PLAINTEXT认证(用户名和密码认证) 3.高级设置 如果设置的是SASL ...