Z
ZHANK
编程在线教程C++ 教程移动语义与右值引用
现代 C++

移动语义与右值引用

左值/右值、std::move、移动构造/赋值、完美转发 forward

移动语义与右值引用

C++11 引入移动语义——不再拷贝数据,而是"窃取"资源的所有权。这是现代 C++ 最重要的性能优化。

学完本章你将: 理解左值/右值、std::move、移动构造/赋值、完美转发。


左值与右值

cpp
int x = 42;         // x 是左值(有名字、可取地址)
int y = x + 1;      // x + 1 是右值(临时值、不可取地址)

int &ref = x;       // 左值引用绑定左值
int &&rref = 42;    // 右值引用绑定右值
// int &&rref2 = x;  // ❌ 右值引用不能绑定左值

std::move —— 左值转右值

cpp
#include <utility>
#include <string>

int main() {
    std::string s1 = "Hello World";
    std::string s2 = s1;              // 拷贝——s1 不变
    std::string s3 = std::move(s1);   // 移动——s1 被"掏空"(高效!)

    // 移动后:s1 处于"有效但未指定"状态,不应再使用
    return 0;
}

⚠️ std::move 不移动任何东西——它只是把左值转换成右值引用。真正的"移动"发生在移动构造函数或移动赋值运算符中。


移动构造与移动赋值

cpp
class Buffer {
    int *data;
    size_t size;
public:
    // 移动构造:窃取 other 的资源
    Buffer(Buffer &&other) noexcept
        : data(other.data), size(other.size) {
        other.data = nullptr;  // 让 other 安全析构
        other.size = 0;
    }

    // 移动赋值
    Buffer &operator=(Buffer &&other) noexcept {
        if (this != &other) {
            delete[] data;           // 释放自己的
            data = other.data;       // 窃取 other 的
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }

    ~Buffer() { delete[] data; }
};

完美转发

cpp
template <typename T>
void wrapper(T &&arg) {
    // std::forward 保持参数的左值/右值属性
    target(std::forward<T>(arg));
}