文章目录
- 一、移动语义
- 1、为什么需要移动语义?
- 2、怎么“偷”?——右值引用(`&&`)
- 3、如何实现移动语义?——移动构造函数/赋值
- 4、什么时候触发移动?
- 5、移动 vs 拷贝
一、移动语义
1、为什么需要移动语义?
传统拷贝(
=
)会复制整个对象,但如果对象很大(如vector<string>
),拷贝开销大。
移动语义的核心思想:“偷资源”,避免不必要的深拷贝,提升性能。
2、怎么“偷”?——右值引用(&&
)
- 右值(临时对象、字面量等) 的生命周期短,可以安全“偷”它的资源。
- 右值引用
&&
用来绑定右值,表示“这个值可以移动”。
示例:
std::string s1 = "Hello";
std::string s2 = std::move(s1); // 把 s1 的资源“偷”给 s2
s1
变成空(资源被移动),s2
直接接管原内存,没有拷贝。
3、如何实现移动语义?——移动构造函数/赋值
类需要定义移动构造函数和移动赋值运算符:
class MyObject {
public:// 移动构造函数(参数是右值引用)MyObject(MyObject&& other) noexcept {data_ = other.data_; // 直接“偷”指针other.data_ = nullptr; // 原对象置空}// 移动赋值运算符MyObject& operator=(MyObject&& other) noexcept {if (this != &other) {delete data_; // 释放自己的资源data_ = other.data_; // “偷”对方的资源other.data_ = nullptr;}return *this;}private:int* data_; // 假设管理动态内存
};
关键点:
- 直接“窃取”资源(如指针),避免深拷贝。
- 把原对象的资源置空(防止重复释放)。
4、什么时候触发移动?
- 显式移动:
std::move(obj)
强制转成右值引用。 - 隐式移动:函数返回临时对象时(编译器优化)。
示例:
std::vector<int> createBigVector() {std::vector<int> v = {1, 2, 3, 4, 5};return v; // 编译器可能优化为移动(而非拷贝)
}auto v = createBigVector(); // 移动构造,无拷贝
5、移动 vs 拷贝
拷贝 | 移动 | |
---|---|---|
操作 | 深复制(完整备份) | “偷”资源(直接接管) |
开销 | 高(内存、时间) | 低(仅指针交换) |
原对象 | 保持不变 | 被置空(资源转移) |
一句话总结:
移动语义通过
&&
和std::move
“偷”临时对象的资源,避免深拷贝,提升性能。适用于管理动态内存的类(如vector
、string
、自定义资源类)。