在C++11之前,函数返回大对象或传递临时变量时常发生不必要的深拷贝,拖慢程序。C++11带来右值引用和move语义,让我们能识别临时对象并转移其资源,从而显著提升性能。

什么是右值引用
右值引用使用T&&语法,只能绑定到右值,也就是临时对象或即将销毁的对象。左值引用T&绑定有名字的对象。通过右值引用,我们可以区分出哪些对象的数据可以被安全搬走。
左值与右值简单对照
| 类别 | 例子 | 能否取地址 |
|---|---|---|
| 左值 | int a = 1; 中的a | 能 |
| 右值 | getObject()返回的临时对象 | 不能 |
move语义如何工作
move语义依赖移动构造函数和移动赋值运算符。它们接受右值引用参数,将源对象的指针等资源直接接管,再把源对象置为空状态,避免拷贝。
手写一个带移动能力的类
下面代码展示一个简化缓冲区类,包含拷贝与移动操作:
#include <iostream>
#include <cstring>
class Buffer {
public:
int* data;
size_t size;
// 构造
Buffer(size_t n) : size(n), data(new int[n]) {}
// 拷贝构造(深拷贝)
Buffer(const Buffer& other) : size(other.size), data(new int[other.size]) {
std::memcpy(data, other.data, size * sizeof(int));
}
// 移动构造(窃取资源)
Buffer(Buffer&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
}
~Buffer() { delete[] data; }
};
int main() {
Buffer a(10);
Buffer b(std::move(a)); // 调用移动构造,a被置空
return 0;
}
std::move做了什么
std::move本身不移动任何数据,它只是把左值强制转换为右值引用,告诉编译器这里允许被移动。真正的资源转移发生在移动构造函数或移动赋值里。
常见性能优化场景
- 函数返回局部大对象,触发移动而非拷贝
- 向vector插入临时对象,减少内存分配
- swap两个对象时直接交换指针
使用注意点
被move后的对象处于有效但未指定状态,不应再使用其值,但可以做销毁或重新赋值。移动操作建议标记为noexcept,这样标准库容器在扩容时会优先使用移动而不是拷贝。
右值引用和move语义不是让程序自动变快,而是给开发者一种安全转移资源的工具,用对地方才能优化性能。
小结
理解右值引用是入口,实现移动语义是手段,std::move是触发方式。在写现代C++时,为自定义类型提供noexcept的移动操作,并合理使用std::move,能明显减少无谓拷贝,让程序更轻快。