一.什么是左值、右值?
C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值。通俗的左值的定义就是非临时对象,那些可以在多条语句中使用的对象。所有的变量都满足这个定义,在多条代码中都可以使用,都是左值。右值是指临时的对象,它们只在当前的语句中有效。举几个列子就更好判断了:
int i = 0;
i为左值,0为右值;
((i>0) ? i : j) = 1;
i、j为左值,0、1为右值;
可见左右值并不是以在赋值=号左右边来区分的,主要看是非零时对象还是零时对象。
还有一些特殊的右值出现在这些表达式中:
1.除非return一个局部变量的时候,否则变量名肯定不是右值:
当返回值类型是基本数据类型时也就是一般的函数,return局部变量时会先将局部变量拷贝到一个零时变量中,这个时候返回的其实是右值(零时对象),可以传入到形参为右值引用的函数中,但是返回值类型确不能为右值引用的;
int put() //虽然queren函数形参为右值引用,但是这边返回值类型为int&&会报错
{
int temp ;
temp = 2;
return temp;
}
int queren(int&& a)
{
cout << "1";
return 1;
}
int main()
{
queren(put());
return 0;
}
2.当return的是全局变量时,返回的就是左值,这个时候
可以函数的返回值类型可以是 int&,即左值引用类型。
3.表达式的返回值是一个值类型的时候,那么当我们对这个表达式求值的时候,返回值所代表的对象可以被看成一个右值。(原理跟普通函数应该是一样的,但是经过测试,既可以是左值也可以是右值优先为右值)
如下面这段代码:Sum初始化时,两个构造函数都可以调用,当然有右值引用构造函数会优先调用
#include <iostream>
#include <vector>
using namespace std;
vector<int> MakeVector(int start,int stop)
{
vector<int> numbers;
for (int i = start; i < stop; i++)
{
numbers.push_back(i);
}
return numbers;
}
class Sum
{
private:
vector<int> numbers;
public:
explicit Sum(const vector<int>& theNumbers)
:numbers{theNumbers}
{
cout << "123\n";
}
explicit Sum(const vector<int>&& theNumbers)
:numbers{theNumbers}
{
cout << "1234\n";
}
int Get()
{
int sum = 0;
for(auto i : numbers)
{
sum += i;
}
return sum;
}
};
int main()
{
Sum sum{MakeVector(1, 10)};
cout << sum.Get() << endl;
return 0;
}
4.表达式的返回值是右值引用的时候,那肯定就是右值。
但是如果临时对象通过一个接受右值的函数传递给另一个函数时,就会变成左值,因为这个临时对象在传递过程中,变成了命名对象。
示例程序 :
void process_value(int& i) {
std::cout << "LValue processed: " << i << std::endl;
}
void process_value(int&& i) {
std::cout << "RValue processed: " << i << std::endl;
}
void forward_value(int&& i) {
process_value(i);
}
int main() {
int a = 0;
process_value(a);
process_value(1);
forward_value(2);
}
运行结果 :
LValue processed: 0
RValue processed: 1
LValue processed: 2
虽然 2 这个立即数在函数 forward_value 接收时是右值,但到了 process_value 接收时,变成了左值。