std::move转换对象的实际移动时机?函数调用是否属于移后使用?
关于std::move的实际移动时机及移后使用的判断
核心结论:std::move本身不触发移动
std::move只是一个类型转换工具,它的唯一作用是把左值强制转换成对应的右值引用类型,全程不会对对象的资源做任何转移操作。
实际移动操作的触发时机
只有当这个被std::move转换出来的右值引用,被用来完成以下操作时,才会触发实际的移动:
- 初始化一个新对象:此时会调用类的移动构造函数,把原对象的资源转移到新对象中。
- 赋值给一个已存在的对象:此时会调用类的移动赋值运算符,完成资源转移。
针对示例代码的分析
对于代码:
f(std::move(a), a.Something())
其中f的定义为f(A a, int x),需要注意两个关键点:
- C++标准未指定函数实参的求值顺序,也就是说
std::move(a)的求值(仅类型转换)和a.Something()的调用顺序是不确定的。 - 真正的移动操作发生在
f的第一个参数A a初始化时——也就是用std::move(a)得到的右值引用去构造这个函数参数的时候,才会调用A的移动构造函数,转移原对象a的资源。
基于求值顺序的不确定性,会出现两种情况:
- 如果先调用
a.Something(),再初始化f的第一个参数(触发移动):此时操作安全,a.Something()调用时原对象状态完整。 - 如果先初始化
f的第一个参数(触发移动),再调用a.Something():此时原对象a已经被移动,其状态仅保证可析构和可赋值(除非类的移动构造函数额外做了保证),调用a.Something()属于移后使用,会导致未定义行为。
因此,这段代码存在潜在的未定义行为风险,属于不安全的写法。
内容的提问来源于stack exchange,提问作者c z
相关产品推荐
相关产品推荐

