半小时掌握C++11之右值引用

99 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

指针和引用

指针是一个变量,存储的是一个地址,指向内存的一个存储单元;

引用是原变量的一个别名,跟原来的变量实质上是同一个东西。

区别:

  • 指针可以在定义的时候不初始化,引用必须在定义的时候初始化
  • 指针可以指向NULL,引用不可以为NULL
  • 指针初始化之后可以再改变,引用不可以
  • 指针和引用都可以作为函数参数,改变实参的值;指针和引用作为函数参数时,指针需要检查是否为空,引用不需要

C++左值和右值

ps:左值--有名字的房子;右值--没有名字的危房

左值的英文简写为“lvalue”,右值的英文简写为“rvalue”。很多人认为它们分别是"left value"、"right value" 的缩写,其实不然。lvalue 是“loactor value”的缩写,可意为存储在内存中、有明确存储地址(可寻址)的数据,而 rvalue 译为 "read value",指的是那些可以提供数据值的数据(不一定可以寻址,例如存储于寄存器中的数据)。

一个左值它可能同时具有左值属性和右值属性,左值属性就是它的房子的名字,右值属性就是指住房子的人,也就是对象的值

C++左值引用

ps:给有名字的房子起个别名。

C++引用,使用 "&" 表示。但此种引用方式有一个缺陷,即正常情况下只能操作 C++ 中的左值,无法对右值添加引用

int num = 10;
int &b = num; //正确
int &b;//错误
int &b = 10; //错误

不支持为右值建立非常量左值引用,但允许使用常量左值引用操作右值。也就是说,常量左值引用既可以操作左值,也可以操作右值

int num = 10;
const int &b = num;
const int &c = 10;

我们知道,右值往往是没有名称的,因此要使用它只能借助引用的方式。这就产生一个问题,实际开发中我们可能需要对右值进行修改(实现移动语义时就需要),显然左值引用的方式是行不通的。

C++右值引用

ps:给没有名字的危房起名字

C++11 标准新引入了另一种引用方式,称为右值引用,用 "&&" 表示。需要注意的,和声明左值引用一样,右值引用也必须立即进行初始化操作,且只能使用右值进行初始化

int num = 10;
//int && a = num;  //右值引用不能初始化为左值
int && a = 10;

和常量左值引用不同的是,右值引用还可以对右值进行修改

int && a = 10;
a = 100;
cout << a << endl;

i++ vs ++i

#include <iostream>
using namespace std;
​
​
int main(int argc, char **argv)
{
    int i = 10;
    int& j = (++i);
    cout<<i<<" "<<&i<<endl;
    cout<<j<<" "<<&j<<endl;
    
​
    return 0;
}
/*
11 0x6ffe14
11 0x6ffe14
*/

++i先加后用,返回的是原来的房子,左值

#include <iostream>
using namespace std;
​
int main(int argc, char **argv)
{
    int i = 10;
    int &&j = (i++);
    cout<<i<<" "<<&i<<endl;
    cout<<j<<" "<<&j<<endl;
    return 0;
}
/*
11 0x7fff97cbc1c8
10 0x7fff97cbc1cc
*/

i++先用后加,返回临时对象,右值

具体用哪个,i++的效率会低一点,因为它产生了临时变量,临时变量的产生和销毁都需要花时间。