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的更多相关文章

  1. C++编译器优化技术:RVO、NRVO和复制省略

    现代编译器缺省会使用RVO(return value optimization,返回值优化).NRVO(named return value optimization.命名返回值优化)和复制省略(Co ...

  2. RVO和NRVO

    返回值优化(Return Value Optimization,简称RVO),是这么一种优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用户返回,那么这个临时对象会消耗一个构造函数(C ...

  3. 第15课 右值引用(2)_std::move和移动语义

    1. std::move (1)std::move的原型 template<typename T> typename remove_reference<T>::type& ...

  4. duang!!!为什么函数能够返回unique_ptr

    C++虐我千百遍,我待C++如初恋 从智能指针说起 对高手而言.指针是上天入地的神器.对新手而言,那简直是灾难的源泉.高级语言如Java,C#都自己主动管理内存.你仅仅管new.不必担心内存释放问题. ...

  5. C++返回值优化

    返回值优化(Return Value Optimization,简称RVO)是一种编译器优化机制:当函数需要返回一个对象的时候,如果自己创建一个临时对象用于返回,那么这个临时对象会消耗一个构造函数(C ...

  6. C++ 11 右值引用以及std::move

    转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46779063 新类型: int和int&是什么?都是类型.int是整数类型,in ...

  7. Effective Modern C++:05右值引用、移动语义和完美转发

    移动语义使得编译器得以使用成本较低的移动操作,来代替成本较高的复制操作:完美转发使得人们可以撰写接收任意实参的函数模板,并将其转发到目标函数,目标函数会接收到与转发函数所接收到的完全相同的实参.右值引 ...

  8. copy elison & RVO & NRVO

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

  9. 返回值优化(RVO)

    C++的函数中,如果返回值是一个对象,那么理论上它不可避免的会调用对象的构造函数和析构函数,从而导致一定的效率损耗.如下函数所示: A test() { A a; return a; } 在test函 ...

  10. 【M20】协助完成“返回值优化(RVO)”

    1.方法返回对象,会导致临时对象的产生,这降低了效率,const Rational operator* (const Rational& lhs,Rational& rhs).有没有什 ...

随机推荐

  1. SpringBoot 项目实战 | 瑞吉外卖 Day02

    该系列将记录一份完整的实战项目的完成过程,该篇属于第二天 案例来自B站黑马程序员Java项目实战<瑞吉外卖>,请结合课程资料阅读以下内容 该篇我们将完成以下内容: 完善登陆系统 新增员工 ...

  2. luoguP1419 寻找段落(二分答案+单调队列)单调队列DP求在区间[l,r] 中长度至少为 m 的最大平均值

    模板:单调队列DP求在区间\([l,r]\) 中长度至少为 \(m\) 的最大平均值 题目链接:Here 题意 给定一个长度为 \(n\) 的序列 \(a_1\) ~ \(a_n\) ,从中选取一段长 ...

  3. vue 状态管理 一、状态管理概念和基本结构

    系列导航 vue 状态管理 一.状态管理概念和基本结构 vue 状态管理 二.状态管理的基本使用 vue 状态管理 三.Mutations和Getters用法 vue 状态管理 四.Action用法 ...

  4. 四、java对mongo数据库增删改查操作

    系列导航 一.linux单机版mongo安装(带密码验证) 二.mongo集群搭建 三.java连接mongo数据库 四.java对mongo数据库增删改查操作 五.mongo备份篇 mongoexp ...

  5. java 对象作为成员变量

    public class Main { private int uplimit; private int value; public Main(int uplimit){ this.uplimit = ...

  6. Go语言安装(Windows10)

    一. 官网下载 https://golang.google.cn/dl/   二. 软件包安装 选择对应的路径进行安装   三. 环境变量设置 1.path 检查系统环境变量Path内已经添加Go的安 ...

  7. Linux 中常见目录的作用

    by emanjusaka from https://www.emanjusaka.top/2024/01/linux-directory-role 彼岸花开可奈何 本文欢迎分享与聚合,全文转载请留下 ...

  8. ARM下KVM虚拟化的损耗验证--redis

    ARM下KVM虚拟化的损耗验证 摘要 看Windows 上面的 Workstation的虚拟机的 网络层的延迟特别高. 突然想之前统计都是直接在本地验证的, 只考虑了虚拟化CPU的性能损耗 没有考虑虚 ...

  9. [转帖]docker 最新版本升级

    文章目录 前言 一.卸载低版本docker 1.1 检查docker版本 1.2 删除docker 二.开始安装 2.1 安装所需依赖 2.2 设置docker yum源 2.3 查看所有可用版本 2 ...

  10. [转帖]Docker相关的概念和原理

    https://www.jianshu.com/p/9737cbe33304 chroot chroot就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录.Docker是利用Linux的 ...