【Effective Modern C++】第五章:右值引用、移动语义和完美转发:29. 认识移动操作的缺点

移动语义是 C++11 最核心的特性之一:它能在满足特定条件时,用低开销的移动操作替代高开销的复制操作,甚至能让 C++98 的代码重新编译后直接获得性能提升。但也正因如此,移动语义的效果和适用范围被普遍夸大,本条款的目的是让开发者理性看待移动语义,避免过度乐观。

移动语义无优势 / 失效的核心场景

移动语义无法带来性能提升、甚至直接退化为复制操作的四类典型场景:

  • 类型本身不支持移动操作:对于 C++98 遗留的未适配类型、不符合编译器默认生成移动操作条件的自定义类型(如声明了复制操作、移动操作或析构函数,或成员 / 基类禁用了移动),移动写法会直接退化为复制,无法带来任何性能提升。
  • 移动操作并不比复制更快:并非所有支持移动的类型都有低开销的实现。比如 std::array,数据直接存储在对象本身而非堆内存,移动需要线性时间逐个处理元素,开销与复制处于同一量级;再比如开启了小字符串优化(SSO)的短 std::string,数据存储在对象内部缓冲区,移动开销与复制几乎无差异。
  • 移动操作被上下文强制禁用 :标准库部分容器操作要求强异常安全保证,若移动操作未声明noexcept,即便有更高效的移动实现,编译器也会强制使用复制操作,避免移动抛异常破坏原有安全约定。
  • 源对象无法触发移动:除极少数例外场景,只有右值能作为移动操作的来源,左值对象无法触发移动,只能执行复制。

假设的适用边界与例外

  • 该保守假设的核心适用场景,是通用模板代码 (无法预知待处理类型是否支持高效移动)、频繁修改的不稳定代码(类型特性可能随时变动),这类场景需要像 C++98 时代一样,保守地处理对象复制。
  • 若开发者明确知晓代码所用类型支持高效移动操作,且调用上下文能合法触发移动,就无需遵循该保守假设,可安全使用移动语义替代复制。

结论

  1. 通用代码场景下,假定移动操作不存在、成本高、未被使用;
  2. 在已知类型特性、明确支持高效移动语义的代码中,无需遵循上述保守假设。

原著在线阅读地址

相关推荐
苏宸啊8 小时前
IPC管道
linux·c++
BestOrNothing_20158 小时前
ROS2 话题通信实战:消息对象、Publisher 发布器与 Subscriber 订阅器保姆级教程
c++·ros2·subscriber·publisher·话题通信
艾iYYY10 小时前
string 类的模拟实现
android·服务器·c语言·c++·算法
为何创造硅基生物10 小时前
C++ virtual void StartNetwork() = 0; // 纯虚:子类必须实现,否则不能 new。
c++
知无不研10 小时前
对套接字的深入理解
linux·服务器·网络·c++·socket·网络套接字
hai31524754312 小时前
FlashAttention C语言(C++)实现(展示版)
c语言·开发语言·c++·人工智能·算法
wuminyu12 小时前
Java锁机制之Java对象重量级锁源码剖析
java·linux·c语言·jvm·c++
郝学胜_神的一滴13 小时前
Qt 高级开发 026:QTabWidget御道,从筑基到化境
c++·qt
apocelipes13 小时前
GNU GCC 多版本函数扩展
c语言·c++·linux编程
代码中介商14 小时前
C++完美转发与引用折叠全解析
开发语言·c++