美文网首页
左值引用右值引用

左值引用右值引用

作者: devilisdevil | 来源:发表于2021-04-03 10:22 被阅读0次

    引用主要就是为了减少一些不必要的拷贝。传的啥就用它的那一份空间

    左值引用

    左值引用:也就是传统的引用,大家都比较熟悉,就是为了给我们的变量起个别名,和取地址然后得到指针其实差不多

    左值引用有个问题,常值/临时变量是不能传给左值引用的,也有办法可以,就是用常量左值引用(前面加个const)

    int &x = 3; // 错误,常值
    auto& a = A(); // 错误,临时值
    const auto& a = A();
    const int &x = 3;
    

    常左值引用也有个问题,我不能修改这个变量,要是我就想要修改呢,而且我也不想另外复制一份对象。(问:为什么不直接设计为常值/临时变量可以给左值引用赋值,然后可以修改?)

    右值引用

    这时就有了右值引用,它只用一份对象的空间,然后跟一般变量一样可以修改。
    (当然你也可以在前面加const,成为常量右值引用 ,没啥意义?不如直接用常量左值引用?)

    右值的关键在于这个值它在赋值完之后我们就不会再使用它了(或者说我们不再依赖它原来的值了,见下面的move语义)。

    move 转换为右值

    所以我们有了move,它可以把不管左值右值(因为模板参数是T&&类型,涉及引用折叠)都转换为右值,可以看到它的实现特别简单,就是用static_cast进行了一个强转

      /**
       *  @brief  Convert a value to an rvalue.
       *  @param  __t  A thing of arbitrary type.
       *  @return The parameter cast to an rvalue-reference to allow moving it.
      */
      template<typename _Tp>
        constexpr typename std::remove_reference<_Tp>::type&&
        move(_Tp&& __t) noexcept
        { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
    

    这样通过move转换一个值为右值之后我们就可以把它这个值内的东西移走了,也就对应了我们为类实现的移动构造/移动拷贝函数了

    比如下面这个例子,这里我们就复用了b1的ptr指针,如果不这样的话,我们可能就得在拷贝构造函数的时候深拷贝一下了,再动态分配一个int。如果这个指针指向的对象特别大那,那移动构造函数的优势就会特别明显了。

    class B {
    private:
        int *ptr;
    public:
        B(int x): ptr(new int(x)) {}
        B(B &&b): ptr(b.ptr) {
            b.ptr = nullptr;
        }
        ~B() {
            delete ptr;
        }
        int* get() {
            return ptr;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        B b1(3);
        B b2(move(b1));
        cout << b1.get() << endl; // 0
        cout << b2.get() << endl; // 0x602000000010
        return 0;
    }
    

    move完一个变量之后,这个东西里面的值因为被(移动构造/拷贝构造函数)移走了(比如把指针赋值为nullptr),我们不应该再依赖原来的变量的值,所以比如像这里的移动构造函数,我们把这个右值对象里的ptr设为0。

    refs

    相关文章

      网友评论

          本文标题:左值引用右值引用

          本文链接:https://www.haomeiwen.com/subject/lwvfkltx.html