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).有没有什 ...
随机推荐
- SpringBoot 项目实战 | 瑞吉外卖 Day02
该系列将记录一份完整的实战项目的完成过程,该篇属于第二天 案例来自B站黑马程序员Java项目实战<瑞吉外卖>,请结合课程资料阅读以下内容 该篇我们将完成以下内容: 完善登陆系统 新增员工 ...
- luoguP1419 寻找段落(二分答案+单调队列)单调队列DP求在区间[l,r] 中长度至少为 m 的最大平均值
模板:单调队列DP求在区间\([l,r]\) 中长度至少为 \(m\) 的最大平均值 题目链接:Here 题意 给定一个长度为 \(n\) 的序列 \(a_1\) ~ \(a_n\) ,从中选取一段长 ...
- vue 状态管理 一、状态管理概念和基本结构
系列导航 vue 状态管理 一.状态管理概念和基本结构 vue 状态管理 二.状态管理的基本使用 vue 状态管理 三.Mutations和Getters用法 vue 状态管理 四.Action用法 ...
- 四、java对mongo数据库增删改查操作
系列导航 一.linux单机版mongo安装(带密码验证) 二.mongo集群搭建 三.java连接mongo数据库 四.java对mongo数据库增删改查操作 五.mongo备份篇 mongoexp ...
- java 对象作为成员变量
public class Main { private int uplimit; private int value; public Main(int uplimit){ this.uplimit = ...
- Go语言安装(Windows10)
一. 官网下载 https://golang.google.cn/dl/ 二. 软件包安装 选择对应的路径进行安装 三. 环境变量设置 1.path 检查系统环境变量Path内已经添加Go的安 ...
- Linux 中常见目录的作用
by emanjusaka from https://www.emanjusaka.top/2024/01/linux-directory-role 彼岸花开可奈何 本文欢迎分享与聚合,全文转载请留下 ...
- ARM下KVM虚拟化的损耗验证--redis
ARM下KVM虚拟化的损耗验证 摘要 看Windows 上面的 Workstation的虚拟机的 网络层的延迟特别高. 突然想之前统计都是直接在本地验证的, 只考虑了虚拟化CPU的性能损耗 没有考虑虚 ...
- [转帖]docker 最新版本升级
文章目录 前言 一.卸载低版本docker 1.1 检查docker版本 1.2 删除docker 二.开始安装 2.1 安装所需依赖 2.2 设置docker yum源 2.3 查看所有可用版本 2 ...
- [转帖]Docker相关的概念和原理
https://www.jianshu.com/p/9737cbe33304 chroot chroot就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录.Docker是利用Linux的 ...