C++返回值拷贝以及std::move

C++拷贝省略:编译器隐形优化与移动语义的协同实践 在C++编程中,对象拷贝是常见的性能瓶颈,尤其在处理大型数据结构或高频调用时。编译器通过拷贝省略技术,在满足as-if规则的前提下消除不必要的拷贝或移动操作,直接从源位置构造目标对象,实现零成本抽象。这项优化技术是现代C++高效值传递的基石,与C++11引入的移动语义协同工作,显著提升程序性能。在C++17标准中,对纯右值初始化的场景强制要求拷贝省略,使得返回临时对象的操作更加高效安全。理解RVO与NRVO的区别至关重要:RVO针对返回临时对象,C++17后强制优化;NRVO针对返回命名局部对象,是编译器可 阅读详情

最近在看《effective modern C++》,到条款二十五,看到了C++返回值拷贝的说明,故做一下总结。并参考了网上的资料。深入理解C++中的RVO

概述

我将以下面的类为例子,说明C++在RVO的情况下以及关闭RVO情况下,其函数返回值是如何返回给调用者的,并给出其汇编代码的说明。环境是Ubuntu Linux,编译器为GCC7.5.0。

class Obj {
public:
    Obj() { // 构造函数
    std::cout << "in Obj() " << " " << this << std::endl;
    }
    Obj(int n) {
    std::cout << "in Obj(int) " << " " << this << std::endl;
    }
    Obj(const Obj &obj) { // 拷贝构造函数
    std::cout << "in Obj(const Obj &obj) " << &obj << " " << this << std::endl;
    }
    Obj(const Obj &&obj) { // 移动构造函数
    std::cout << "in Obj(const Obj &&obj) " << &obj << " " << this << std::endl;
    }
    Obj &operator=(const Obj &obj) { // 赋值构造函数
    std::cout << "in operator=(const Obj &obj)" << std::endl;
    return *this;
    }
    Obj &operator=(const Obj &&obj) { // 移动赋值构造函数
    std::cout << "in operator=(const Obj &&obj)" << std::endl;
    return *this;
    }
    ~Obj() { // 析构函数
    std::cout << "in ~Obj() " << this << std::endl;
    }
private:
    int n;
};

关闭RVO

编译命令加上-fno-elide-constructors表示关闭RVO 优化开关。定义函数fun1,并调用。

//test28_RVO.cpp
Obj fun1() {
  Obj obj;
  // do sth;
  return obj;
}

int main() {
    Obj a = fun1();
    return 0;
}

编译:g++ -fno-elide-constructors -g -o test28_RVO test28_RVO.cpp。
结果打印:如下图所示。

  • 定义拷贝构造函数以及移动构造函数的情况下:
    在这里插入图片描述

  • 定义拷贝构造函数而未定义移动构造函数的情况下:
    在这里插入图片描述

结果分析:从打印可以分析出,在关闭RVO优化的情况下,C++返回一个对象会调用拷贝构造函数(或者移动构造函数)2次。分析其汇编代码,可知,在main函数调用函数fun1()的时候,调用者会将一个栈的地址传递给fun1()。在函数fun1()内,当调用构造函数创建obj之后,会将obj拷贝到这个栈的地址,作为一个临时对象。函数fun()调用结束之后,会再调用一次拷贝构造函数,临时对象拷贝到接收者即a中。
在这里插入图片描述

在RVO下

代码和上面的相同。

//test28_RVO.cpp
Obj fun1() {
  Obj obj;
  // do sth;
  return obj;
}

int main() {
    Obj a = fun1();
    return 0;
}

编译:g++ -g -o test28_RVO test28_RVO.cpp。
结果打印:如下图所示。
在这里插入图片描述

结果分析:在启用RVO优化的情况下,只调用了一次构造函数,拷贝构造函数没有被调用。
从汇编代码结果可以看出,main函数将地址-0x1c(%rbp)传递给函数fun1(),之后,fun1()在调用Obj构造函数的时候,直接在这个地址上进行构造,免去了临时对象的创建以及拷贝。
在这里插入图片描述

RVO的条件

《modern effective c++》中指出,在开启RVO之后,返回局部对象只有在满足以下两个条件的情况下,编译器才会进行RVO优化。
(1)局部对象与函数返回值的类型相同。
(2)局部对象就是要返回的东西。函数形参不满足要求。
注意:当函数不同控制路径返回不同局部变量时,不会进行拷贝消除的操作,因为其不知道要返回哪个对象。

返回值为std::move的情况

代码如下:

Obj fun2() {
  Obj obj;
  // do sth;
  return std::move(obj);
}

int main() {
    Obj a = fun2();
    return 0;
}

编译:g++ -g -o test28_RVO test28_RVO.cpp。
结果打印:如下图所示

  • 定义拷贝构造函数以及移动构造函数的情况下:
    在这里插入图片描述

  • 定义拷贝构造函数,未移动构造函数的情况下(之所以编译器未报错,是因为const修饰的左值形参能够接收一个右值实参):
    在这里插入图片描述

结果分析:从汇编代码中可以看出,main将变量a的地址传递给fun2()。fun2()创建Obj obj,然后调用移动构造函数将obj移动到a中。
在这里插入图片描述

C++ std::move 用法示例 头文件中,它是一个模板函数,接受一个参数并返回该参数的右值引用。它的作用是告诉编译器,我们希望将对象转为右值,以便进行移动语义的操作。是一个非常有用的函数,它用于将对象转移给其他地方,通常是用于实现高效的移动语义。这表明我们的对象首先通过默认构造函数进行了创建,然后通过移动构造函数进行了移动操作。由于返回值使用了移动语义,编译器会进行返回值优化,避免了拷贝构造函数的调用。这表明我们的对象首先通过默认构造函数进行了创建,然后通过移动构造函数进行了移动操作。在上面的示例中,我们定义了一个名为。 阅读详情

相关推荐

std::move功能

容器操作:当向容器中插入元素时,如果元素类型支持移动语义, std::move 可以将元素移动到容器中,避免拷贝。- 函数返回值:在函数返回对象时,可以使用 std::move 将局部对象的资源移动到函数外部,而不是进行拷贝。std::move 是C++ 中的一个函数,其功能是将对象的资源所有权进行转移,以实现移动语义,减少不必要的拷贝,提高程序性能。在上述代码中,通过 std::move 将 str 移动到 vec 中, str 的资源被转移,其内容变为空字符串。// 输出vector中的字符串。

谢谢大家的关注和点赞!这里只有纯纯的知识干货,没有一句废话。希望能实实在在帮到大家~要是觉得有用,别忘了给我点支持哟,你 448

c++11的函数返回值要不要std::move()

比较返回一个对象,到底该怎么写? // 类型一 std::string getTimeNowString() { string str = "2010-05-04"; return str; } // 类型二 std::string getTimeNowString() { string str = "2010-05-04"; return std::move(str); } // 类型三 std::string& getTimeNowString() {

robinfoxnan的专栏 2763

告别连接难题:Windows 11下Multisim主数据库稳定运行终极配置指南

本文详细解析了Windows 11下Multisim 14.0主数据库连接失败的三大根源,并提供了四步终极解决方案,包括系统环境优化、软件权限配置、注册表修复和网络验证绕过技巧。通过实测数据对比,本方案显著提升了启动速度和稳定性,解决了电子仿真中的常见连接问题。

weixin_33738555的博客 435

一文讲透c++中std::move

std::move是C++11提供的一个函数模板,它可以将一个左值转换为一个右值引用,从而可以触发移动语义。使用std::move可以提高性能和避免不必要的拷贝。但是也要注意不要滥用std::move,因为它可能会导致一些问题:使用std::move后的对象可能会处于一种未定义或者无效的状态,不能再进行正常的操作。使用std::move可能会阻止编译器进行一些优化,比如返回值优化。使用std::move可能会破坏类的封装性和异常安全性。

行走的漂流瓶的博客 2922

DDR3性能优化实战:如何用Xilinx MIG控制器实现800MHz稳定读写(7系列FPGA版)

本文深入探讨了在Xilinx 7系列FPGA上使用MIG控制器实现DDR3存储器800MHz稳定高速读写的实战优化技巧。文章聚焦于高级时序调优、Bank Machine调度策略、用户接口设计优化以及利用ILA进行信号完整性调试,旨在帮助工程师突破性能瓶颈,实现接近理论峰值的稳定带宽,并为进一步冲刺更高频率提供进阶调参指南。

seed的博客 778

FPGA之串口收发字符串之(四)——串口屏USART_HMI介绍

之前对串口各模块的设计都做了相关介绍。这里介绍串口屏的相关知识。 本次项目使用的串口屏型号是陶晶驰串口屏TJC3224T024_011,这个型号的串口屏的资料在官网可以找到。本文抛转引玉,简单介绍以便在本工程中更好的应用。 下图是该串口屏的实物图: 一般地,使用单片机或者嵌入式MCU控制串口屏,都会用到串口,同样地,在FPGA中实现也是类似,不过稍微复杂,具体代码设计过程中有以下问题需要...

隔壁old余的博客 7495

什么情况下需要在 C++ 中使用 return std::move(X)

介绍一下 C++ 中 return std::move 的使用场景。

Kovnt的博客 2013

学习海康VisionMaster之表面缺陷滤波

本文介绍了VisionMaster中表面缺陷滤波技术的应用。该技术通过数学变换抑制背景干扰、增强缺陷特征,适用于电池铝壳、垫圈/螺丝等无纹理背景的表面缺陷检测(划痕、凹坑、异物等)。操作流程包括:图像导入、轮廓定位、位置修正、参数设置(重点讲解滤波核尺寸/数量/标准差等关键参数的调整策略)。文章通过案例演示了如何通过多方向滤波响应识别表面划伤,并指出需结合blob分析进一步优化检测结果。该技术对工业质检具有实用价值,参数设置需结合缺陷特征与背景特性灵活调整。

yuhouxiyang的专栏 2829

【C++11】分析return std::move返回局部对象的必要性

在返回局部对象时使用std::move也许是不必要的,因为编译器会自动应用返回值优化(RVO),所以return std::move到底有没有必要呢

xy286285810的博客 1353

MTK(camera篇)Camera整体点亮

本文介绍了在MTK平台上添加新Camera Sensor的驱动开发流程。主要内容包括:1)MTK Camera采用HAL3架构,驱动层主要负责sensor电源控制和寄存器操作;2)详细说明了添加新sensor需要在多个文件中进行的修改,包括设备树配置、内核头文件、驱动列表、电源序列等;3)特别指出需要配置I2C地址表,并导入tuning文件和metadata文件以完善ISP处理流程。文章提供了完整的文件修改清单,涵盖了从内核层到HAL层的完整开发过程,为MTK平台Camera Sensor驱动开发提供了具体

weixin_49303682的博客 361

使用CloudCompare和CANUPO进行点云分类的编程指南

在本文中,我们将介绍如何使用CloudCompare和CANUPO库进行点云分类的编程。CloudCompare是一款功能强大的开源点云处理软件,而CANUPO是一个用于点云分类和分割的C++库。这只是一个简单的点云分类示例,CANUPO库还提供了其他更高级的功能和算法,以满足各种点云分类需求。该函数接受点云数据、地面点掩码和非地面点掩码作为输入,并将分类结果存储在这两个掩码向量中。完成安装后,我们可以开始编写点云分类的代码。最后,我们遍历点云数据,并根据地面点和非地面点的掩码将结果打印出来。

ByteWhisper的博客 1059

函数返回使用std::move()避免复制

vector&lt;string&gt; fun() { vector&lt;string&gt; str; str.emplace_back("aaaaaaaaaaaaaaaaaaa"); str.emplace_back("aaaaaaaaaaaaaaaaaaa"); str.emplace_back("aaaaaaaaaaaaaaaaaaa"); ...

闲人的专栏 6092

在 SAP S/4HANA Cloud Public Edition 中掌控 ABAP 生命周期管理:One-Off、Multi-Off 与 Scalable Delivery 的落地方法论

本文系统梳理了SAP S/4HANA Cloud Public Edition中ABAP扩展开发的三种生命周期管理模式:One-Off适用于企业内部扩展,通过Import Collection在三系统间流转;Multi-Off面向少量客户交付,基于gCTS和Git实现不连接系统间的传输;Scalable Delivery则将扩展产品化为add-on,支持规模化分发。文章结合RAP、OData等实际开发场景,对比分析了各模式的特点与适用边界,为国内团队提供了符合Public Cloud要求的开发与交付实践建议

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1496

深入浅出RVO、NRVO以及std::move的策略与影响

在C++编程实践中,理解返回值优化(Return Value Optimization, RVO)和命名返回值优化(Named Return Value Optimization, NRVO)对于编写高效的代码至关重要。这些编译器优化技术可以显著减少不必要的对象拷贝,优化程序的性能。同时,std::move的出现增加了对于对象资源管理的精细控制,但其滥用可能会破坏编译器的优化。本文将深入探讨RVO、NRVO以及std::move之间的关系和影响。

qq_42896106的博客 1042

基于STM32设计的盲人智能导盲杖

本设计基于STM32单片机,开发了一种面向视障人群的智能导盲杖系统。系统以STM32F103C8T6为核心控制器,集成了超声波测距、语音提示、环境光检测、GPS定位及4G通信等多种功能模块。

647

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C++进阶之右值引用std::move:用法实例(四百零六)

本篇目的:C++进阶之右值引用std::move:用法实例基本概念std::move 是 C++11 引入的标准库函数模板,定义于<utility>头文件中。它的作用是将一个左值强制转换为右值引用,从而触发移动语义。功能std::move 不进行任何实际的“移动”操作,只是类型转换工具。其主要用途是在对象赋值或构造时,启用移动构造函数或移动赋值运算符,避免昂贵的深拷贝。使用限制被 std::move 修饰的对象之后状态未定义,仅适用于临时资源转移场景。

Android系统攻城狮 909

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C++ C11 移动语义和右值引用

对于含有堆内存的类,我们需要提供深拷贝的拷贝构造函数,如果使用默认构造函数,会导致堆内存的重复删除。,这样就避免了对临时对象的深拷贝,提高了性能。但上面的深拷贝可行,但在。默认构造函数是浅拷贝。没有深拷贝,只有浅拷贝。

waltWu0705的博客 1339

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++核心准则-F.48 不要返回使用std:move从局部变量获得的右值引用​

F.48: Don't return std::move(local) F.48 不要返回使用std:move从局部变量获得的右值引用 Reason(原因) With guaranteed copy elision, it is now almost always a pessimization to expressly use std::move in a return statement...

面向对象思考 4278

C++返回值优化演进:从拷贝灾难到移动语义与强制省略

在C++编程中,函数返回值的传递方式直接影响程序性能。早期C++98标准下,按值返回大对象往往引发多次拷贝,成为性能瓶颈,开发者常借助输出参数或裸指针规避,却牺牲了可读性。C++11引入移动语义,通过右值引用实现资源转移,使返回开销降至常数级别。C++17进一步强制复制省略,让纯右值返回零拷贝成为标准行为。理解这些演进,有助于根据场景选择正确的返回值策略,合理应用RVO和移动语义,编写既高效又清晰的现代C++代码。

weixin_29722783的博客 225

探索 std::move

C++里通常分为左右值,但标准里更细化 这里需要明确右值的概念: 纯右值 prvalue 是没有标识符、不可以取地址的表达式,一般也称之为“临时对象”。 最常见的情况有: 返回非引用类型的表达式,如 x++、x + 1、make_shared(42) 除字符串字面量之外的字面量,如 42、true C++11 开始,C++ 语言里多了一种引用类型—右值引用。右值引用的形式是 T&&,比左值引用多一个 & 符号。 我们使用右值引用的目的是实现移动,而实现移动的意义是减少运行的开销

L-Super的博客 1701

move std 函数 示例_右值引用和std:move()

右值rvalues是怎么产生的?想必你知道,当对象没有命名时,它就是一个右值。一般来说,右值是一个临时的对象,作为函数调用的返回或者其他操作的结果,存在于栈中:从一个函数调用的返回值会转变成一个右值。也就是说,一旦你调用返回一个对象,但这个对象的命名又从来没有存在过,它就变成了右值。同样的,调用一个函数会返回一个右值。返回的值没有命名。Move构造函数与右值一起使用Move构造函数与拷贝构造函数类...

weixin_36474829的博客 556

C++返回值优化(RVO)原理与实践:消除拷贝提升性能

在C++编程中,函数返回值传递常涉及临时对象的构造与拷贝,这是影响程序性能的关键环节。编译器通过返回值优化技术,能够将函数内部构造的对象直接放置在调用方的目标内存位置,从而消除不必要的拷贝开销。这项优化不仅提升了资源管理类(如容器、字符串)的传递效率,更与现代C++的移动语义形成协同,为编写高性能代码提供了底层保障。理解RVO的工作原理、实施条件及其与std::move的交互,有助于开发者在实际工程中避免常见陷阱,编写出更利于编译器优化的代码。本文通过具体示例解析了RVO在工厂函数、STL容器等场景中的应用

weixin_34025151的博客 294

鼓励使用以const引用传参代替值传参_右值引用和std:move()

右值rvalues是怎么产生的?想必你知道,当对象没有命名时,它就是一个右值。一般来说,右值是一个临时的对象,作为函数调用的返回或者其他操作的结果,存在于栈中:从一个函数调用的返回值会转变成一个右值。也就是说,一旦你调用返回一个对象,但这个对象的命名又从来没有存在过,它就变成了右值。同样的,调用一个函数会返回一个右值。返回的值没有命名。Move构造函数与右值一起使用Move构造函数与拷贝构造函数类...

weixin_39575565的博客 1408

C++杂记——返回值优化(RVO,Return Value Optimization)、具名返回值优化 (NRVO,Named Return Value Optimization)

返回值优化(RVO):当函数返回一个对象的临时副本时,编译器可能会调用移动构造函数来优化性能,尤其是在对象较大的情况下。

czw 616

C++右值引用

-----在没有返回值优化的情况下,拷贝构造函数调用了两次,一次是GetA() 函数内部创建的对象返回后构造一个临时对象产生的。在C++中,当函数返回一个对象时,如果这个对象是通过值传递的,则会经历复制构造过程即:copy construct当GetA()调用时,它创建了一个局部对象A,调用构造函数,输出construct:1当GetA()返回时,这个局部对象的生命周期即将结束,因此需要创建一个临时对象来保存返回值,此时调用复制构造函数,输出copy construct:1。

weixin_51883798的博客 1066

C++ 返回值优化 RVO

C++ 返回值优化 RVO引子返回值优化 RVORVO 限制参考 在调试 C++ 拷贝和移动系列构造函数时候,发现构造函数调用和预期不太一样,经过查阅相关资料,发现是返回值优化(RVO)从中做梗。了解了事实真相后,今天就和大家聊聊这个 RVO。 引子 直接看一个例子: #include <iostream> class A { public: A (){ std::cout << "A(): addr= " << this << st

Dong_HFUT的博客 6525
上一篇: snprintf和strcpy和strncpy的区别
下一篇: ld脚本简述
FirMoonLight
博客等级 码龄10年 16粉丝 33原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值