&
) & 右值引用 (&&
) 详解C++ 中的左值引用 (&
) 和 右值引用 (&&
) 用于 操作变量(对象),控制 生命周期、优化拷贝 和 提升性能。
✅ 可以取地址 &
,并且能持续存在(即生命周期长)。
✅ 可以出现在赋值号(=
)左侧,可被修改。
int a = 10; // ✅ `a` 是左值
a = 20; // ✅ 左值可以赋值
常见左值
int x
、std::string name
)arr[0]
)*ptr
)int& foo()
)✅ 不能取地址 &
,是临时的、短生命周期的对象。
✅ 只能出现在赋值号(=
)右侧,不能再赋值。
int x = 5 + 10; // ✅ `5 + 10` 是右值
常见右值
10
, 'c'
, 3.14
)a + b
)int foo()
)❌ 错误示例
&(5 + 10); // ❌ 右值不能取地址
(5 + 10) = 42; // ❌ 右值不能赋值
&
)✅ 左值引用可以绑定左值,让变量通过别名访问。
int a = 10;
int& ref = a; // ✅ 左值引用,ref 绑定 a
ref = 20; // ✅ 修改 ref 也会修改 a
⚠️ 不能绑定右值
int& r = 5; // ❌ 不能用左值引用绑定右值
&&
)✅ 右值引用只能绑定右值,允许"偷" 资源,提高性能。
int&& r = 5; // ✅ 右值引用
r = 10; // ✅ `r` 仍然是变量,可以修改
⚠️ 不能绑定左值
int a = 10;
int&& r = a; // ❌ 不能用右值引用绑定左值
✅ 用 std::move()
转换左值为右值
int&& r = std::move(a); // ✅ `a` 变成右值
#include
#include
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
的深拷贝,提升效率!
std::forward
)std::forward
保留 t
的左值或右值特性。
template <typename T>
void wrapper(T&& arg) {
func(std::forward<T>(arg)); // ⚡ 传递 `arg` 的原始类型
}
std::forward
保留参数原始状态,适用于泛型编程。
类型 | 绑定左值 | 绑定右值 | 示例 |
---|---|---|---|
左值(Lvalue) | ✅ | ❌ | int a = 10; |
右值(Rvalue) | ❌ | ✅ | 5 + 10 |
左值引用(int& ) |
✅ | ❌ | int& ref = a; |
右值引用(int&& ) |
❌ | ✅ | int&& r = 5; |
右值引用 (&&
) 是 C++11 的核心优化工具!
常用于:
std::move()
(强制转换为右值)std::forward()
(完美转发)移动构造(Move Constructor) 是 C++11 引入的一种优化机制,用于高效转移对象的资源,避免昂贵的深拷贝(Deep Copy)。
关键点
T(T&& other)
接受右值引用(&&
)。other
置空)。class Example {
public:
int* data;
// 复制构造函数(深拷贝)
Example(const Example& other) {
data = new int(*other.data); // 拷贝数据
}
};
✅ 问题:
class Example {
public:
int* data;
// 移动构造函数
Example(Example&& other) noexcept : data(other.data) {
other.data = nullptr; // ✅ 避免释放同一块内存
}
};
✅ 优势:
std::vector
)。#include
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
被置空,避免二次释放!
std::move()
的作用std::move()
将左值转换为右值,触发移动构造。
Example a(100);
Example b = a; // ❌ 复制构造(慢)
Example c = std::move(a); // ✅ 移动构造(快)
std::move(a)
强制 a
变为右值,使 c
调用 移动构造,而不是 复制构造。
Example createExample() {
return Example(200); // ✅ 可能触发移动构造
}
Example obj = createExample(); // ✅ 调用移动构造
std::vector
(避免拷贝,提高性能)std::vector<Example> vec;
vec.push_back(Example(300)); // ✅ 直接移动构造,提高效率
std::move()
转换左值Example a(400);
Example b = std::move(a); // ✅ 触发移动构造
#include
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;
}
std::vector
移动构造优化#include
#include
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())
直接移动构造,不调用拷贝构造,提高性能!
操作 | 复制构造(深拷贝) | 移动构造(转移所有权) |
---|---|---|
数据存储 | 复制一份新数据 | 直接转移指针 |
效率 | 慢(分配新内存) | 快(不分配新内存) |
适用场景 | 需要保留原数据 | 只需转移资源 |
函数签名 | T(const T&) |
T(T&&) noexcept |
移动构造比拷贝构造更高效,用于:
return Example();
)。std::vector
复制大对象(emplace_back()
)。std::move()
强制触发移动构造。