You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中已被移动的对象能否再次被移动?

关于C++中被移动后对象的复制/再次移动安全性问题

核心结论

被移动后的对象处于有效但未指定的状态,C++标准仅保证能对其执行赋值操作和销毁操作,其他操作(复制、再次移动)的安全性完全取决于对象类型的具体实现,不能一概而论。

一、被移动后的对象能否复制或再次移动?

  • 标准无强制安全承诺:“未指定状态”意味着对象内部值不确定,除非该类型的官方文档明确约定了移动后的具体状态(比如部分标准库类型会承诺移动后对象为空),否则无法预知复制/再次移动的结果。
  • 具体场景示例:
    • 对于std::string、std::vector这类标准库类型,主流实现会将被移动后的对象置为空状态,此时复制会得到空对象,再次移动也不会触发问题——但这是实现方的约定,而非C++标准的强制要求。
    • 对于自定义类型,如果移动构造函数未将源对象置于确定安全状态(比如仅转移资源但未把源对象的指针置空),再次移动可能导致重复释放资源,复制则可能得到包含无效资源的对象,触发未定义行为。

二、容器重分配时再次移动已被移动的对象是否安全?

以vector重分配为例:

  • vector重分配时优先调用元素的移动构造函数(若该函数标记为noexcept),否则会退用复制构造函数。
  • 若移动构造函数是noexcept且实现正确:只要移动构造能处理任何有效状态的源对象(哪怕是未指定状态),再次移动就是安全的——因为移动构造的要求本身是“移动后源对象仍处于有效但未指定状态”,所以即使源对象已被移动过,只要它仍有效,移动构造就能正常执行(结果仍未指定,但不会触发未定义行为)。
  • 若使用复制构造函数:情况和前文一致,复制结果未指定,若复制操作依赖源对象的特定状态,可能触发未定义行为。

实操建议

  1. 永远不要依赖被移动后对象的具体状态,除非类型文档明确说明。
  2. 自定义类型实现移动语义时,建议将被移动后的源对象置于确定的安全状态(比如把指针置空、容器清空),确保后续复制或再次移动不会出问题。
  3. 对于标准库类型,可放心依赖主流实现的约定(比如移动后为空),但需明确这不是标准强制要求,极端场景下可能有例外。

内容的提问来源于stack exchange,提问作者ABu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:52:32