引用


引用可以看成是 C++ 封装的指针,用来传递它所指向的对象。在 C++ 代码中实际上会经常和引用打交道,但是通常不会显式地表现出来。引用的基本原则是在声明时必须指向对象,以及对引用的一切操作都相当于对原对象操作。另外,引用不是对象,因此不存在引用的数组、无法获取引用的指针,也不存在引用的引用。

注意引用类型不属于对象类型,所以才需要 reference_wrapper 这种设施。

引用主要分为两种,左值引用和右值引用。此外还有两种特殊的引用:转发引用和垂悬引用,不作详细介绍。另外,本文还牵涉到一部分常值的内容,请用

常值 一文辅助阅读。

左值引用

如果你不知道什么是左值和右值,可以参考

值类别 页面。

如果一个表达式返回的是左值,那么这个表达式被称为左值表达式。右值表达式亦然。

通常我们会接触到的引用为左值引用,即绑定到左值的引用,但 const 的左值引用可以绑定到右值。以下是来自 参考手册 的一段示例代码。

左值引用最常用的地方是函数参数,通过左值引用传参可以起到与通过指针传参相同的效果。

右值引用 (C++ 11)

右值引用是绑定到右值的引用。右值 可以在内存里也可以在 CPU 寄存器中。另外,右值引用可以被看作一种 延长临时对象生存期的方式

在上述代码中,r3 是一个右值引用,引用的是右值 s1 + s1r2 是一个左值引用,可以发现 右值引用可以转为 const 修饰的左值引用

一些例子

++ii++

++ii++ 是典型的左值和右值。++i 的实现是直接给 i 变量加一,然后返回 i 本身。因为 i 是内存中的变量,因此可以是左值。实际上前自增的函数签名是 T& T::operator++();。而 i++ 则不一样,它的实现是用临时变量存下 i,然后再对 i 加一,返回的是临时变量,因此是右值。后自增的函数签名是 T T::operator++(int);

移动语义和 std::move(C++11)

在 C++11 之后,C++ 利用右值引用新增了移动语义的支持,用来避免对象在堆空间的复制(但是无法避免栈空间复制),STL 容器对该特性有完整支持。具体特性有 移动构造函数移动赋值 和具有移动能力的函数(参数里含有右值引用)。 另外,std::move 函数可以用来产生右值引用,需要包含 <utility> 头文件。

注意:一个对象被移动后不应对其进行任何操作,无论是修改还是访问。被移动的对象处于有效但未指定的状态,具体内容依赖于 stl 的实现。如果需要访问(即指定一种状态),可以使用该对象的 swap 成员函数或者偏特化的 std::swap 交换两个对象(同样可以避免堆空间的复制)。

注意上述代码仅在 C++11 之后可用。

函数返回引用

让函数返回引用值可以避免函数在返回时对返回值进行拷贝,如

你不能返回在函数中的局部变量的引用,如果一定要在函数内的变量。请使用动态内存。例如如下两个函数都会产生悬垂引用,导致未定义行为。

当右值引用指向的空间在进入函数前已经分配时,右值引用可以避免返回值拷贝。

参考内容

  1. C++ 语言文档——引用声明
  2. C++ 语言文档——值类别
  3. Is returning by rvalue reference more efficient?
  4. 浅谈值类别及其历史

贡献者:@Ir1dXD@ksyx@Jacder@CoderOJ@mgt@Margatroid@Jacob

本页面最近更新:2/3/2023, 12:00:00 AM更新历史

发现错误?想一起完善? 在 GitHub 上编辑此页!

本页面的全部内容在 CC BY-SA 4.0SATA 协议之条款下提供,附加条款亦可能应用

评论

0 条评论
未登录用户


Copyright © 2016 - 2023 OI Wiki Team

最近更新:fd2ec2c, 2023-02-03

联系方式:Telegram 群组 / QQ 群组