最近在学move语义,在网上搜索到的文章看不懂,左值引用、右值引用...搞的好乱,问了一下deepseek,举了几个例子,然后我好像懂了move的大致用法,当然右值引用还是不懂,本文章大概总结一下关于move的用法,当做笔记了hhh(根据deepseek的回答总结出来的),很浅,如果想深入理解move可以跳过。
通俗解释 move 语义
想象一下你有一本书,你现在想把它给你的朋友。
不用 move(拷贝): 你跑去复印店,把整本书复印一份,然后把复印本给你的朋友。你自己还留着原版书。这个过程(复印)既费钱(消耗内存)又费时间(消耗CPU周期)。
用 move(移动): 你直接走过去,把原版书递到你朋友手里。这本书的所有权就从你转移到了你朋友。你手上不再拥有这本书(但它处于一个“有效但空”的状态,比如你可以再买一本新的放回手里)。
移动语义的核心思想就是“所有权转移”,它避免了不必要的深层复制,极大地提升了性能,尤其是对于管理着大量资源的对象(如字符串、向量、文件句柄等)。
1、用于容器操作
最常见的场景,用于高效地将元素放入或移出容器。
#include <iostream>
#include <queue>
#include <functional>
using namespace std;
int main() {
queue<function<void()>> q;
// 向队列中添加一个任务
q.push([]() { cout << "Hello from task!\n"; });
cout<<"q.size()="<<q.size()<<endl;
cout<<"q.front()的调用:";
q.front()(); //调用队列中的第一个函数
// 正确(高效)的方式:移出任务
function<void()> task = move(q.front()); // 这里用 move!
cout<<"task的调用:";
task(); // 执行任务
cout<<"-------------------------"<<endl;
//此时队列大小仍为1,但是队首元素已不可用,因为被转移了
cout<<"q.size()="<<q.size()<<endl;
//如果强行使用,会抛出异常
try{
q.front()();
}
catch(const std::exception& e){
std::cerr << e.what() << '\n';
}
return 0;
}
输出:

2、拷贝对象
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
//使用move
void test01(){
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1);
// 现在 v1 不再是 {1,2,3} 了,它很可能是一个空向量
cout<<"v1:";
for(int& i:v1){
cout<<i<<' ';
}
cout<<endl;
cout<<"v2:";
for(int& i:v2){
cout<<i<<' ';
}
cout<<endl;
}
//不使用move
void test02(){
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = v1;
// 现在 v1 仍是 {1,2,3}
cout<<"v1:";
for(int& i:v1){
cout<<i<<' ';
}
cout<<endl;
cout<<"v2:";
for(int& i:v2){
cout<<i<<' ';
}
cout<<endl;
//将v2下标为1的元素修改为100
v2[1]=100;
cout<<"v1:";
for(int& i:v1){
cout<<i<<' ';
}
cout<<endl;
cout<<"v2:";
for(int& i:v2){
cout<<i<<' ';
}
cout<<endl;
}
int main(int argc, const char *argv[]){
test01();
cout<<"--------------"<<endl;
test02();
return 0;
}
输出:

3、实现高性能的swap
template<class T>
void swap(T& a, T& b) {
T temp = std::move(a); // a 的资源移动给 temp
a = std::move(b); // b 的资源移动给 a
b = std::move(temp); // temp 的资源(原是a的)移动给 b
}
// 整个过程没有任何昂贵的拷贝,只有三次低成本的所有权转移。
4、构造函数的初始化列表中初始化类成员
#include<iostream>
using namespace std;
#include<functional>
class MyClass {
std::string m_name;
public:
// 使用移动语义来初始化成员,避免拷贝
MyClass(std::string name) : m_name(std::move(name)) {
// 此时参数 name 已被移空,不能再使用它
cout<<"name: "<<name<<endl;
}
void printInfo(){
cout<<"m_name: "<<m_name<<endl;
}
};
int main(int argc, char const *argv[]){
std::string s = "Hello";
MyClass obj(s); // 构造 obj 时,s 被拷贝给参数 name,然后 name 被移动给 m_name
obj.printInfo();
return 0;
}
输出:

C++11 move移动语义详解
1014

被折叠的 条评论
为什么被折叠?



