一.对象和值
我们可以分配并使用没有名字的对象,比如用new创建对象,也能为有些看起来不寻常的表单时赋值比如*p[a+10]=7。因此我们用一个名字来表示“内存中的某个东西”。这个东西就是对象的最基本含义。对象是指一块连续存储区域,左值是指向对象的一条表达式。其字面意思是能用在复制运算符左侧的东西。但其实不是所有的左值都能用在赋值运算的左侧,左值也有可能只是某个常量。
二.左值和右值
为了补充完善左值的含义,引入了右值,简单理解,右值是指不能作为左值的值为右值,比如函数的返回值为临时值。当考虑对象的寻址、拷贝、移动等操作时,有两个属性非常关键:
1.有身份:在程序中有对象的名字,或指向该对象的指针,或该对象的引用,这样我们就能判断两个对象是都相等或者对象发生了改变。
2.可移动:能把对象的内容移动出来,比如我们能把他的只移动到其他某处,剩下的对象处于合法但未指定的状态,与拷贝有差别的。
void f(vector<string>& vs)
{
vector<string>& v2 = std::move(vs); //移动vs到v2
//...
}
此处std::move(vs)是一个特别值,他有明显的身份,我们能像vs一样引用它,兵器我们明显给与了将其值移出的许可。
通常情况下,判断某个表达式是左值还是右值,最常用的有以下 2 种方法。
- 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值。
- 有名称的、可以获取到存储地址的表达式即为左值;反之则是右值。
虽然 C++98/03 标准不支持为右值建立非常量左值引用,但允许使用常量左值引用操作右值。也就是说,常量左值引用既可以操作左值,也可以操作右值。
三.问题辨析:
1.Why is rvalue reference to an integer legal
As my understanding, rvalue reference is also a reference, which means that it will algo point to some variable, just like the reference does.
For example,
const int &ref = 1;
The reference ref points to the pure rvalue 1, which can’t be modified, that’s why the compiler force us to use const.
const T&的初始化不一定非的是左值,甚至可以不是T类型的:
1)首先如果必要的话先执行目标为T的隐式类型转化;
2)然后将所得的值至于一个T类型的临时变量中;
3)最后把这个临时变量作为初始值。
double& dr = 1; //错误:此处需要左值
const double& cdr{1} //OK
上面最后一句的初始化过程可以理解为:
double temp = double{1}; //首先用给定的值创建临时变量
const double& cdr{temp} ; //然后用这个临时变量作为cdr的初始值
Another example,
Bar&& GetBar()
{
Bar b;
return std::move(b);
}
This function will return a dangling reference because b is destructed after returning.
In a word, rvalue reference is algo a reference.
Now I’m confused. Please check the following code:
int &&rref = 1;
If rvalue reference is also a reference, so rref now points to the pure rvalue 1, which shouldn’t be compilable as my understanding, because if it’s compilable, what if I execute rref = 2? Does this mean that the pure rvalue is changed: 1 becomes 2?
But gcc told me that it was compilable…
Why? Why don’t we need const int &&rref = 1?
A quote from cppreference
i)The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.
With a link to additional details here
ii)Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference, with the following exceptions:
a temporary bound to a return value of a function in a return statement is not extended: it is destroyed immediately at the end of the return expression. Such function always returns a dangling reference.
a temporary bound to a reference member in a constructor initializer list persists only until the constructor exits, not as long as the object exists. (note: such initialization is ill-formed as of DR 1696). (until C++14)
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
a temporary bound to a reference in the initializer used in a new-expression exists until the end of the full expression containing that new-expression, not as long as the initialized object. If the initialized object outlives the full expression, its reference member becomes a dangling reference. (since C++11)
a temporary bound to a reference in a reference element of an aggregate initialized using direct-initialization syntax (parentheses) as opposed to list-initialization syntax (braces) exists until the end of the full expression containing the initializer. (since C++20)
2.右值引用地址是可以输出,右值没有地址:
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int &&a = 100;
cout << a << endl;
a = 10;
cout << a << " " << &a << endl;
return 0;
}
输出结果:
Program returned: 0
Program stdout
100
10 0x7ffd95701324
右值引用变量是一个左值。 就像我们下面这个函数:
void process(int&& temp)
{
}
temp 就是一个左值一样。 可以去地址,传给其他函数也是一个左值引用。
换句话说,只要有名字,就是左值。 用更准确的话来说,声明int && a表明它 “只能绑定右值对象”, 但它一旦绑定之后,自己有了名字,也可以取地址(绑定的右值对象生存周期被延长),它也就是一个左值。
比如 你不可以写:
int data=100;
int&& a=data; 因为data是左值。 a不能绑定左值。
参考链接:
1.https://stackoverflow.com/questions/64084983/why-is-rvalue-reference-to-an-integer-legal
2.C++程序设计语言;