美文网首页
【C++】左值与右值

【C++】左值与右值

作者: 离原春草 | 来源:发表于2022-04-12 16:40 被阅读0次

日拱一卒,功不唐捐

日常工作中经常遇到右值引用的相关逻辑,或者想要通过右值引用来优化程序性能,不过因为对右值引用只有一知半解,因此常常需要查阅资料才能拼凑出只鳞片羽的局部印象,难以构建整体理解,这里将平时搜集到的一些资料与自己的一些理解汇总到一起,从而避免每次的重复搜索与整理。

这里由于不是(也没有时间)系统的去搜集所有的内容,因此输出的结论会显得凌乱与分散,寄希望于等到内容丰富到一定程度再进行梳理。

C++的值类别

value总的来说,可以分成glvalue跟rvalue两类,其中glvalue指的是泛左值(generalized lvalue),rvalue为右值。

泛左值包含左值lvalue与将亡值xvalue(expiring value,快要销毁的对象),而右值rvalue同样包含纯右值prvalue(pure rvalue)与将亡值xvalue。

这里就有人要问了,将亡值这个反骨崽到底是左值还是右值?我只能说视情况而定,根据需要,可以是左值,也可以是右值,举个例子:

MoveTest GetMoveTestInstance()
{
  MoveTest t;
  return t;
}

MoveTest k = GetMoveTestInstance();

上面这个构造函数,如果我们为MoveTest类定义了移动构造函数,那么GetMoveTestInstance中的将亡值t就是右值,否则就是左值。

具名的右值是左值
所谓具名的右值,指的是如果某个用&&表示的对象有了名字,那么这个对象就会被当成左值来使用,下面给个例子:

#include <iostream>
#include <vector>
#include <set>
#include <assert.h>
using namespace std;

class MoveTest
{
public:
    int i = 0;
    MoveTest(int data) : i( data )
    {
        cout << "Move Test Constructor" << endl;
     }

    MoveTest( const MoveTest& other ) :  i(other.i)
    {
        cout << "Move Test Copy Constructor" << endl;
    }

    MoveTest( MoveTest&& other ) : i( other.i )
    {
        cout << "Move Test Move Constructor" << endl;
    }

    MoveTest& operator=( const MoveTest& other )
    {
        if( this != &other )
        {
            i = other.i;
            cout << "Move Test Copy Assignment" << endl;
        }
        return *this;
    }

    MoveTest& operator=( MoveTest&& other )
    {
        if( this != &other )
        {
            i = other.i;
            cout << "Move Test Move Assignment" << endl;
        }
        return *this;
    }
};

void CheckCopy( MoveTest& Input )
{
    MoveTest Local = Input;
    cout << "CheckCopy:" << Local.i << endl;
}

void CheckMoveAssign( MoveTest&& Input )
{
    MoveTest Local( 0 );
    Local = Input;
    cout << "CheckMoveAssign:" << Local.i << endl;
}

void CheckMove( MoveTest&& Input )
{
    MoveTest Local = Input;
    cout << "CheckMove:" << Local.i << endl;
}

void Test()
{
    MoveTest Original( 3 );
    CheckCopy( Original );
    //CheckMove( Original ); // error: an rvalue cannot be bound to an lvalue
    CheckMove( move(Original) );
    CheckMoveAssign( MoveTest(2) );
}

int main()
{
    Test();
    return 0;
}

运行结果为:

Move Test Constructor
Move Test Copy Constructor
CheckCopy:3
Move Test Copy Constructor
CheckMove:3
Move Test Constructor
Move Test Constructor
Move Test Copy Assignment
CheckMoveAssign:2

首先,我们要想将一个左值赋值给一个右值的形参,需要调用std::move接口进行显式转换;
其次,在CheckMove函数中,MoveTest Local = Input;我们理解应该调用移动构造函数进行构造,但实际上调用了拷贝构造函数,这就是前面说的具名的右值会被看成是左值导致的,既然是左值,那么自然使用拷贝构造函数。

既然具名的右值是左值,那么这种右值有什么作用呢?注意,右值提出的主要目的是降低数据拷贝的时间与空间消耗,而即使被看成左值来使用,这个避免拷贝的特性还依然是正常使用的。

另一个问题是,如果我们想要对具名的右值调用移动构造函数要怎么办,通过传参数的方式真的没有办法做到了吗?当然,不是,C++为我们提供了将左值转换为右值使用的接口std::move,我们只需要将函数实现改为如下形式,就能够调用移动构造函数了:

void CheckMove( MoveTest&& Input )
{
    MoveTest Local = move(Input);
    cout << "CheckMove:" << Local.i << endl;
}

参考

[1]. c++移动构造函数

相关文章

  • C++11那些难事:左值引用、右值引用与完美转发

    上一篇C++那些难事:左值与右值搞明白左值与右值,下面讲解左值引用与右值引用。 1. 左值引用与右值引用 左值右值...

  • 左值右值引用和移动构造

    左值与右值 左值引用右值引用 C++ 11中用&表示左值引用,用&&表示右值引用 (move函数可以把一个) 进...

  • C++ 左值与右值 右值引用 引用折叠 => 完美转发

    左值与右值 什么是左值?什么是右值? 在C++里没有明确定义。看了几个版本,有名字的是左值,没名字的是右值。能被&...

  • 右值引用

    参考资料 谈谈 C++ 中的右值引用C++11 左值、右值、右值引用详解

  • C++11右值引用、移动语义和完美转发

    左值、右值 在C++中,所有的值不是左值,就是右值。左值是指表达式结束后依然存在的持久化对象,右值是指表达式结束后...

  • C++11之move语义

    要理解c++11的move语义,就需要理解C++中的左值和右值和临时对象的概念。 左值与右值和临时对象的简单介绍:...

  • C++ 左值与右值

    做一个信息时代的独立阅读者。 前几天看到《C++ Primer》中提到了左值右值的概念,当时也没太当回事,以为就是...

  • 【C++】左值与右值

    日拱一卒,功不唐捐 日常工作中经常遇到右值引用的相关逻辑,或者想要通过右值引用来优化程序性能,不过因为对右值引用只...

  • 理解c++中左值、右值

    说明 c/c++程序员肯定都知道左值、右值,理解好左值、右值有利于我们更好的使用c++语言。下面是我的学习笔记 概...

  • C++11: 右值引用

    C++11: rvalue 右值 rvalue & lvalue(右值与左值) 左值与右值的定义是比较复杂,下边仅...

网友评论

      本文标题:【C++】左值与右值

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