std::move仅执行类型转换,将左值转为右值引用以启用移动语义;真正移动操作由移动构造函数或赋值运算符完成,且应声明noexcept以避免容器退化为拷贝。

为什么 std::move 不真的移动东西?
因为 std::move 只是类型转换——它把左值强制转成右值引用类型,让编译器知道“你可以拿走这个对象的资源了”。它本身不调用任何移动构造函数,也不释放内存、不清空数据。真正干活的是你写的移动构造函数或移动赋值运算符。
- 常见错误:对一个已用
std::move转换过的对象继续读取或调用非noexcept成员函数,结果未定义(比如访问vec.size()后又调用vec.data(),而移动后vec可能为空或指针为nullptr) - 使用场景:返回局部容器、交换两个大对象、push_back 临时对象时避免深拷贝
- 参数差异:
T&&是通用引用(可能绑定左值或右值),而std::move(x)的结果永远是右值引用类型,只用于触发移动语义
移动构造函数必须加 noexcept 吗?
不是“必须”,但不加会极大影响性能——比如 std::vector 在扩容时,若元素类型移动构造函数没声明 noexcept,它就宁愿拷贝也不移动,因为要保证强异常安全。
- 常见错误:写了移动构造函数但忘了加
noexcept,结果std::vector<bigobject></bigobject>插入时仍发生大量拷贝 - 性能影响:加了
noexcept后,标准容器能放心用移动替代拷贝;否则退化为保守策略 - 兼容性注意:C++11 起要求移动操作尽可能
noexcept,且所有标准库移动操作都假设如此
std::move 后还能用原对象吗?
可以访问,但只能调用不依赖内部状态的成员函数(如 empty()、size(),前提是你的移动构造函数留好了合法值),不能假设内容还存在。标准只要求移动后的对象处于“有效但未指定状态”(valid but unspecified state)。
- 常见错误:移动后直接
std::cout 或 <code>obj[0] = 42;,结果段错误或逻辑错乱 - 安全做法:移动后立即重置或赋新值,比如
std::move(obj); obj.clear();(如果clear()是轻量的) - 实际建议:除非明确需要复用对象内存(如对象池),否则移动后就别再碰它——把它当成“已移交”的凭证
哪些类型默认有移动语义?
标准库中绝大多数资源管理类型(std::vector、std::string、std::unique_ptr 等)在 C++11 起都默认提供了移动构造/赋值,且标记为 noexcept。但自定义类不会自动获得——你得自己写。
立即学习“C++免费学习笔记(深入)”;
- 常见错误:以为继承了
std::vector就自动有移动语义,其实派生类若没显式定义,编译器可能生成删除的移动函数(尤其当基类有用户定义的析构函数时) - 参数差异:含
const成员、引用成员、或用户定义了拷贝但没定义移动的类,编译器不会合成移动操作 - 检查方法:用
static_assert(std::is_move_constructible_v<mytype>);</mytype>编译期验证
std::move 就变快”,而是整套协作机制:类型要可移动、移动操作要 noexcept、调用方要主动转换、使用者要尊重移动后的对象状态。漏掉任一环,优化就失效。










