C++ 左值引用 & 右值引用 && std::move()左值改右值 移动构造函数()

C++ 左值引用 (&) & 右值引用 (&&) 详解

C++ 中的左值引用 (&)右值引用 (&&) 用于 操作变量(对象) ,控制 生命周期、优化拷贝提升性能


1. 什么是左值(Lvalue)和右值(Rvalue)

(1)左值(Lvalue)

可以取地址 &,并且能持续存在 (即生命周期长)。

可以出现在赋值号(=)左侧,可被修改。

cpp 复制代码
int a = 10;  // ✅ `a` 是左值
a = 20;      // ✅ 左值可以赋值

常见左值

  • 变量int xstd::string name
  • 数组元素arr[0]
  • 解引用指针*ptr
  • 返回左值引用的函数int& foo()

(2)右值(Rvalue)

不能取地址 & ,是临时的、短生命周期 的对象。

只能出现在赋值号(=)右侧,不能再赋值。

cpp 复制代码
int x = 5 + 10;  // ✅ `5 + 10` 是右值

常见右值

  • 字面量(10, 'c', 3.14
  • 临时变量(a + b
  • 返回非引用的函数(int foo()

错误示例

cpp 复制代码
&(5 + 10);  // ❌ 右值不能取地址
(5 + 10) = 42;  // ❌ 右值不能赋值

2. 左值引用(Lvalue Reference, &

左值引用可以绑定左值,让变量通过别名访问。

cpp 复制代码
int a = 10;
int& ref = a;  // ✅ 左值引用,ref 绑定 a
ref = 20;  // ✅ 修改 ref 也会修改 a

⚠️ 不能绑定右值

cpp 复制代码
int& r = 5;  // ❌ 不能用左值引用绑定右值

3. 右值引用(Rvalue Reference, &&

右值引用只能绑定右值,允许"偷" 资源,提高性能。

cpp 复制代码
int&& r = 5;  // ✅ 右值引用
r = 10;  // ✅ `r` 仍然是变量,可以修改

⚠️ 不能绑定左值

cpp 复制代码
int a = 10;
int&& r = a;  // ❌ 不能用右值引用绑定左值

std::move() 转换左值为右值

cpp 复制代码
int&& r = std::move(a);  // ✅ `a` 变成右值

4. 右值引用的用途

(1)移动语义(避免深拷贝,提高性能)

cpp 复制代码
#include <iostream>
#include <string>

class MoveExample {
public:
    std::string data;
    
    // 右值引用的移动构造函数
    MoveExample(std::string&& str) : data(std::move(str)) {
        std::cout << "Move Constructor Called" << std::endl;
    }
};

int main() {
    std::string temp = "Hello";
    MoveExample obj(std::move(temp));  // ✅ 调用移动构造
    return 0;
}

⚡ 右值引用避免了 temp 的深拷贝,提升效率!


(2)完美转发(std::forward

std::forward<T>(t) 保留 t 的左值或右值特性。

cpp 复制代码
template <typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg));  // ⚡ 传递 `arg` 的原始类型
}

🔹 std::forward<T> 保留参数原始状态,适用于泛型编程。


5. 左值 & 右值 & 引用 总结

类型 绑定左值 绑定右值 示例
左值(Lvalue) int a = 10;
右值(Rvalue) 5 + 10
左值引用(int& int& ref = a;
右值引用(int&& int&& r = 5;

🚀 右值引用 (&&) 是 C++11 的核心优化工具!
常用于:

  1. 移动语义(提高性能,减少拷贝)
  2. std::move()(强制转换为右值)
  3. std::forward<T>()(完美转发)

C++ 移动构造(Move Constructor)详解

1. 什么是移动构造?

移动构造(Move Constructor)C++11 引入的一种优化机制 ,用于高效转移对象的资源,避免昂贵的深拷贝(Deep Copy)

📌 关键点

  • T(T&& other) 接受右值引用(&&
  • 转移资源所有权 ,避免拷贝大对象
  • 清空原对象,避免释放同一块内存(other 置空)。

2. 移动构造 vs. 复制构造

(1)复制构造(深拷贝)

cpp 复制代码
class Example {
public:
    int* data;
    
    // 复制构造函数(深拷贝)
    Example(const Example& other) {
        data = new int(*other.data);  // 拷贝数据
    }
};

问题

  • 拷贝对象的所有数据新分配内存性能较低

(2)移动构造(转移资源,不拷贝)

cpp 复制代码
class Example {
public:
    int* data;
    
    // 移动构造函数
    Example(Example&& other) noexcept : data(other.data) {
        other.data = nullptr;  // ✅ 避免释放同一块内存
    }
};

优势

  • 资源直接转移(不重新分配内存)。
  • 性能更高 (适合大对象,如 std::vector)。

3. 移动构造函数的实现

cpp 复制代码
#include <iostream>

class Example {
private:
    int* data;
public:
    // 构造函数
    Example(int value) : data(new int(value)) {
        std::cout << "Constructor: allocated " << *data << std::endl;
    }

    // 移动构造函数
    Example(Example&& other) noexcept : data(other.data) {
        other.data = nullptr;  // 清空原对象,避免释放
        std::cout << "Move Constructor: moved resource" << std::endl;
    }

    // 析构函数
    ~Example() {
        if (data) {
            std::cout << "Destructor: freeing " << *data << std::endl;
            delete data;
        } else {
            std::cout << "Destructor: nothing to free" << std::endl;
        }
    }
};

int main() {
    Example a(10);
    Example b(std::move(a));  // ✅ 调用移动构造
    return 0;
}

输出

复制代码
Constructor: allocated 10
Move Constructor: moved resource
Destructor: nothing to free
Destructor: freeing 10

b 拿走了 a 的资源,a 被置空,避免二次释放!


4. std::move() 的作用

std::move()左值转换为右值 ,触发移动构造

cpp 复制代码
Example a(100);
Example b = a;          // ❌ 复制构造(慢)
Example c = std::move(a); // ✅ 移动构造(快)

🔥 std::move(a) 强制 a 变为右值 ,使 c 调用 移动构造 ,而不是 复制构造


5. 什么时候调用移动构造?

(1)返回局部对象(C++11 及更高版本,RVO 可能优化)

cpp 复制代码
Example createExample() {
    return Example(200);  // ✅ 可能触发移动构造
}
Example obj = createExample();  // ✅ 调用移动构造

(2)存入 std::vector(避免拷贝,提高性能)

cpp 复制代码
std::vector<Example> vec;
vec.push_back(Example(300));  // ✅ 直接移动构造,提高效率

(3)手动 std::move() 转换左值

cpp 复制代码
Example a(400);
Example b = std::move(a);  // ✅ 触发移动构造

6. 复制 & 移动的完整实现

cpp 复制代码
#include <iostream>
class Example {
private:
    int* data;
public:
    // 构造函数
    Example(int value) : data(new int(value)) {}

    // 复制构造
    Example(const Example& other) : data(new int(*other.data)) {
        std::cout << "Copy Constructor: deep copy" << std::endl;
    }

    // 移动构造
    Example(Example&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move Constructor: moved" << std::endl;
    }

    ~Example() {
        if (data) delete data;
    }
};

int main() {
    Example a(100);
    Example b = a;  // ❌ 复制构造(慢)
    Example c = std::move(a);  // ✅ 移动构造(快)
    return 0;
}

7. std::vector 移动构造优化

cpp 复制代码
#include <vector>
#include <iostream>

class Example {
public:
    Example() { std::cout << "Default Constructor" << std::endl; }
    Example(const Example&) { std::cout << "Copy Constructor" << std::endl; }
    Example(Example&&) noexcept { std::cout << "Move Constructor" << std::endl; }
};

int main() {
    std::vector<Example> vec;
    vec.reserve(3);  // 预分配内存,防止 `realloc` 触发拷贝构造

    vec.push_back(Example());  // ✅ 直接使用右值,调用移动构造
    return 0;
}

输出

复制代码
Default Constructor
Move Constructor

push_back(Example()) 直接移动构造,不调用拷贝构造,提高性能!


8. 移动构造 vs. 复制构造

操作 复制构造(深拷贝) 移动构造(转移所有权)
数据存储 复制一份新数据 直接转移指针
效率 慢(分配新内存) 快(不分配新内存)
适用场景 需要保留原数据 只需转移资源
函数签名 T(const T&) T(T&&) noexcept

9. 结论

🚀 移动构造比拷贝构造更高效,用于:

  1. 返回临时对象 (如 return Example();)。
  2. 避免 std::vector 复制大对象emplace_back())。
  3. 手动 std::move() 强制触发移动构造
相关推荐
程序媛学姐8 分钟前
SpringCloud消息总线:Bus事件广播与配置动态刷新
java·开发语言
Vic1010112 分钟前
Java 中装饰者模式与策略模式在埋点系统中的应用
java·开发语言·策略模式
Lzc77419 分钟前
C++进阶——哈希表的实现
c++·哈希表的实现
三体世界22 分钟前
C++ STL 序列式容器之(三)-- List
java·c语言·开发语言·c++·windows·list·visual studio
爱的叹息27 分钟前
java 设置操作系统编码、jvm平台编码和日志文件编码都为UTF-8的操作方式
java·开发语言·jvm
愚戏师30 分钟前
C++:向Lambda传递参数与捕获
开发语言·c++
编程乐趣31 分钟前
一个纯.Net开发的JavaScript执行引擎
开发语言·javascript·.net
努力学习的小廉34 分钟前
【C++】 —— 笔试刷题day_8
开发语言·c++
你好,明天,,1 小时前
OpenCV三维解算常用方法C++
c++·数码相机·opencv
万亿少女的梦1681 小时前
基于Ebay拍卖网站成交价格的影响因素分析
java·开发语言·网络安全