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

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

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

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

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

假设的适用边界与例外

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

结论

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

原著在线阅读地址

相关推荐
xlp666hub18 小时前
Leetcode 第三题:用C++解决最长连续序列
c++·leetcode
会员源码网20 小时前
构造函数抛出异常:C++对象部分初始化的陷阱与应对策略
c++
xlp666hub1 天前
Leetcode第二题:用 C++ 解决字母异位词分组
c++·leetcode
不想写代码的星星1 天前
static 关键字:从 C 到 C++,一篇文章彻底搞懂它的“七十二变”
c++
xlp666hub2 天前
Leetcode第一题:用C++解决两数之和问题
c++·leetcode
不想写代码的星星2 天前
C++继承、组合、聚合:选错了是屎山,选对了是神器
c++
不想写代码的星星3 天前
std::function 详解:用法、原理与现代 C++ 最佳实践
c++
樱木Plus5 天前
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)
c++
blasit7 天前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
肆忆_8 天前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++