C++11之move移动语义

C++11 move移动语义详解

最近在学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;
}

输出:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值