之前我们聊过左值右值的基础概念,今天我们来讲讲C++里的两个神秘工具函数 —— std::move
和 std::forward
🧙♂️
对左值与右值右疑惑的小伙伴看这里~:
C++左值、右值你分清了吗
深入理解 C++ 中的引用:左值引用与右值引用
🧭 std::move:不是移动,而是“允许移动”
移动语义的目的是通过窃取资源(而不是拷贝)来提高性能,这在处理大对象时尤其有用。
但是很多人看到 std::move(obj)
,下意识以为这就把 obj
的内容“搬走”了,但实际上:
std::move
不移动任何东西。它只是一个类型转换工具,把一个左值变成一个右值,从而允许调用移动构造或移动赋值函数。
🌟 示例:触发移动构造
#include <iostream>
#include <vector>
class TestClass {
public:
std::vector<int> data;
TestClass() {
data.push_back(1);
data.push_back(2);
data.push_back(3);
std::cout << "默认构造\n";
std::cout << "This vector size : " << data.size() << std::endl;
}
TestClass(const TestClass& other) {
std::cout << "拷贝构造\n";
}
TestClass(TestClass&& other) noexcept {
std::cout << "移动构造\n";
std::cout << "Other vector size brefore move: " << other.data.size() << std::endl;
std::cout << "This vector size brefore move: " << data.size() << std::endl;
data = std::move(other.data); // 此处窃取资源
std::cout << "Other vector size after move: " << other.data.size() << std::endl;
std::cout << "This vector size after move: " << data.size() << std::endl;
}
};
int main() {
TestClass a;
std::cout << "----------------------\n";
TestClass b = std::move(a); // a 是左值,但 std::move(a) 是右值,从而触发移动构造
}
执行结果:
默认构造
This vector size : 3
----------------------
移动构造
Other vector size brefore move: 3
This vector size brefore move: 0
Other vector size after move: 0
This vector size after move: 3
🌀 std::forward:完美地保留值类别
在泛型编程中,我们经常写模板函数接收不同类型的参数。
如果你希望它既能传递左值又能传递右值,那么你就需要完美转发(Perfect Forwarding)。
🌟 示例:完美转发
#include <iostream>
void print(int& x) {
std::cout << "左值引用\n";
}
void print(int&& x) {
std::cout << "右值引用\n";
}
template<typename T>
void wrapper(T&& arg) {
print(std::forward<T>(arg)); // 保留原始值类别
}
int main() {
int a = 10;
wrapper(a);
std::cout << "-----------\n";
wrapper(42);
}
执行结果:
左值引用
-----------
右值引用
核心机制:
🌱 转发引用T&&
在模板中会根据传入参数的类型推导为左值引用或右值引用。
🌱 std::forward<T>(arg)
的作用:将 arg
按照 T
的值类别原样传递。
注意:
不要在非模板函数中使用T&&,因为它只是普通的右值引用。
🧩小结
std::move
的本质是类型转换:将左值强转为右值,以触发移动操作std::forward
的本质是条件转发:保留原始值类别,实现完美转发
希望本文对你有帮助~
本文首发于微信公众号《Linux在秋名山》,欢迎大家关注~