C++ | 右值引用与std::move()

右值引用

  • 左值:可以被取地址的变量或值

  • 右值:无法被修改,无法取地址的值。一般为临时变量。

  • 左值引用:

    • 常引用,只能指向左值

    • 或者通过 const 的方式指向一个右值

      const int & a = 17;
      

      所以,函数形参定义为const type & var 时,既可以接受变量,也可以接受右值。如std::vectorpush_back()

      void push_back(const type & val);
      

      如果没有const,那v.push_back(17)这样的代码就无法编译通过了。

  • 右值引用: 只能指向右值的引用,指向左值则无法通过编译

    • 使用右值引用,本质上将一个右值变成了一个左值:int &&a = 17;

      变量a是一个左值,所以右值引用是一个左值

    • 对于函数形参而言,定义为type && var将只接受为右值的实参。

    为什么会有右值引用的出现呢?
    // 类Obj数据的定义
    class Obj{
        int _size;
        char *_buf;
    };
    

    当我们定义Obj类的构造函数时,如果我们想用对象a来初始化对象b,有时候初始化后我们还想要继续使用对象a,那这时候的构造函数就需要将对象a的数据完全复制给对象b

    Obj(const Obj &o){
        _size = o._size;
        _buf = new char[_size];
        for(int i=0;i<_size;i++) _buf[i] = o._buf[i];
    }
    
    (这样称为深拷贝。浅拷贝是简单地复制值,包括指针,经过浅拷贝之后的两个指针只是指向了同一个地址;而深拷贝会在堆内存中另外申请空间给新指针或者新引用)

    而有的时候对象a只是一个临时变量(右值),用完即弃。这时候直接将对象a的数据移动给对象b即可:

    Obj(const Obj &o){
        _size = o._size;
        _buf =  o._buf;
        o._buf = nullptr;
    }
    
    (注意到,在移动构造函数中,末尾有o._buf = nullptr。之所以要将被移动数据的对象中的指针/引用置为空指针,原因是避免在对象a和对象b的析构函数中都对该地址进行delete

    但实际上,以上的移动构造函数是无法实现的,因为const使得传入对象无法被修改。因此,为了实现移动构造函数,C++11引入了右值引用:

    Obj(Obj && o){
        _size = o._size;
        _buf =  o._buf;
        o._buf = nullptr;
    }
    

    这样问题就得到解决了。当构造函数时传入参数为右值时,会调用Obj(Obj && o);若是左值,则会调用Obj(const Obj & o)

    此时,又有另外一个问题,如果使用一个对象a是一个对象而非一个临时变量,但我依旧想要使用移动数据的方式来构造函数(对象a在之后不再使用),那该怎么办呢?

    如果依旧使用Obj b(a)来构造,那还是会复制构造。要使用移动构造,就得使用某种方法将对象a变成右值。而函数std::move()就起到这个作用:

    std::move(var) --- 作用是类型转换:接受一个左值作为参数,返回其右值引用

    所以此时使用 Obj b(std::move(a)) ,就用移动构造初始化了对象b

    很多类的成员函数实际上都实现了这两种方法,比如vector的push_back():
    // std::vector方法定义
    void push_back(const type & value);
    void push_back(type && value);
    
    vector<string> vs;
    string str = "hello world";
    vs.push_back(str);	             // 此时是传入左值,push_back会深拷贝str
    vs.push_back(std::move(str));	 // 此时传入了右值,push_back浅拷贝str作为vs中的元素
    			                     // 同时str被置为空,不能再被使用
    
posted @   C111-CR  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示