C++右值引用

一.对象和值

我们可以分配并使用没有名字的对象,比如用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 种方法。

  1. 可位于赋值号(=)左侧的表达式就是左值;反之,只能位于赋值号右侧的表达式就是右值。
  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++程序设计语言;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值