欢迎光临散文网 会员登陆 & 注册

C++ 左引用和右引用

2023-02-09 15:08 作者:神兮兮的喵社长  | 我要投稿

说明1:

首先我们区分什么是左值和右值,有一个很好区分左值和右值的方式,就是是否可以对表达式取地址!!可以获取地址的表达式就是左值,且持久性变量都是左值,反之则是右值。左值引用和右值引用都是对象的别名而已,左值引用就是左值的别名,右值引用就是右值的别名。所以左值引用只能绑定左值,右值引用只能绑定右值,我们不能将一个右值引用类型变量绑定到一个右值引用。因为变量都是左值!我们可以对右值引用类型变量取地址!但是有一个例外,const左值引用可以绑定到右值。这看起来好像有点难以理解,我们用代码实际解释一下。

int i = 42; //i是左值,可以对i取地址

int &r = i; //r是左值引用,绑定左值i

右值引用无法和右值引用类型变量绑定,因为右值引用类型变量是一个左值,所有持久性变量都是左值。可以取地址的变量是持久性变量,反之是临时性变量。


说明2:

我们可以将左值引用看为一个对象的别名。左值引用的声明包含一个可选的说明符列表,后面跟一个引用声明符。左值引用必须被初始化,且不能再指向另外一个对象或设置为null。:

在C++11中,引入了右值引入,可以通过一个可变引用指向rvalue,但是不能绑定到lvalue,因此右值引用可以检测一个值是否是临时对象。 类似于左值引用使用&,右值引用使用&&,可以是const/non-const

说明3:

在 C++ 中,引用类型是一种复合类型,可以分为左值引用常引用右值引用

在了解什么是左值引用和右值引用之前,我们需要先了解什么是左值和右值。由于 C++ 本身没有给出左值和右值的标准定义,

  • 可以取地址的,有名称的,非临时的是左值

  • 不可取地址,匿名的,临时的是右值

左值引用

左值引用是我们平时在编程时最常使用到的。引用的作用相当于是给变量取了“别名”。引用本身没有自己的内存地址,因此在定义的过程当中必须进行初始化,而且一旦和变量进行了绑定,则无法解绑并重新绑定。另外,左值引用只能和左值进行绑定

常引用

常引用是指利用 const 修饰的引用类型。由于引用本身已经绑定不可解绑,因此所用的 const 引用都是底层 const,即引用对象不能改变(俗称常引用)。由于常引用引用的是常量,所以可以使用表达式,字符串字面值等常量为常引用进行初始化。

右值引用

右值引用是 C++ 新标准中引入的。右值引用的定义形式为:

右值引用的主要作用有两个:

  1. 实现移动语义

  2. 实现完美转发

作用一、移动语义的实现。

C++ 中的 “移动语义” 是相对于 “拷贝语义” 的一个概念。在引入”移动语义“之前,C++ 主要利用拷贝功能来实现对象的移动,通常的操作是在新分配好的内存空间上调用拷贝构造函数,将旧对象复制到新内容中,然后再释放旧对象。而”移动语义“的引入使得 C++ 允许直接将旧对象的所有权直接转让给新分配的内存空间,这样一来避免了旧对象的复制与释放,极大地提高了代码的运行效率。如果说 ”拷贝语义“ 描述了对象的拷贝功能,那么”移动语义“ 描述的则是对象的剪切功能。(注:转让意味着将所有权交给新区域的同时,还要放弃自身的所有权)

C++ 中的 ”移动语义“ 主要利用右值引用来实现。C++ 允许将一个右值引用 rr 绑定到一个临时对象上,从而将该临时对象的生命周期延长到与 rr 一样长。这样一来,我们便可以通过 rr 在程序当中的任何位置访问该临时对象。


作用 二:完美转发

完美转发主要应用于这样一组场景:我们需要将一个函数的参数原封不同地传递给另一个函数。在 C++ 中,函数参数除了类型和值以外,还有 const 和 non-const 以及 左值和右值 两组属性。所谓的完美转发,就是在将一个函数的参数传递给另一个参数时,参数的类型、值以及所有属性都不能改变,这在泛型编程当中有着广泛的应用。

针对模板函数的实现,C++ 11 在原有的正常绑定规则上增加一个新的绑定规则 —— 引用折叠,具体规则如下:

  • 若模板函数 func 的形参类型为 T&, 则不论传递给 func 的实参是左值还是右值,一律统统折叠为左值引用

  • 若模板函数 func 的形参类型为 T&&, 则传递给函数的左值实参折叠为左值引用,右值实参折叠为右值引用

总之一句话:在定义函数模板时使用右值引用做形参,能够保证参数的属性(const 属性和 左/右值属性)不发生变化。

在 代码 2 中,虽然 i 和 ci 是左值,但由于发生了引用折叠,所以 f1(i) 和 f1(ci) 是合法的。在引用折叠的规则下,无论一个函数有多少个参数,借助右值引用我们都只需要定义一个函数模板即可,这就大大减少了编程时的低效劳动。

右值引用和常引用的异同

相同点:

  • 右值引用和常引用都允许和表达式,字符串字面值等进行绑定

不同点:

  • 常引用可以和普通变量绑定,而右值引用只能绑定到右值上面

  • 常引用类型的变量是不可修改的,而右值引用类型的变量是可以修改的

引用和指针的区别

  1. 引用和指针都是复合类型,但指针是变量,有自己的内存地址,而引用是别名,没有自己的内存地址

  2. 引用一旦定义就必须初始化,而指针可以先定义,然后再初始化

  3. 引用一旦和某个具体的变量绑定后,就不能再解除绑定,而指针变量在指向某一变量后,依然可以改变指向。

  4. 存在多维指针,但不存在多维引用【C++ 中不允许直接定义引用的引用,但可以通过类型别名或者模板类型参数间接定义】

  5. 因为引用没有自己的内存地址,所以只存在引用指针的引用,但不存在指向引用的指针

注:实际上,C++ 当中引用的实现也是利用到了 const 指针来实现的,但是由于编译器做了一部分工作,因此引用本身对于程序员而言是透明的。







C++ 左引用和右引用的评论 (共 条)

分享到微博请遵守国家法律