首页 > 代码库 > 翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述

翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述

本文系对「C++ Rvalue References Explained」 该文的翻译,原文作者:Thomas Becker

该文较详细的解释了C++11右值引用的作用和出现的意义,也同时被Scott Meyers推荐,全文共分11个部分,我将利用业余时间,分别翻译。

受笔者水平所限,可能叙述会出现些许问题,还望多多指正。

部分名词为了保持含义和方便理解,并未翻译成中文,有的在括号内给出了常见的中文翻译。


目录

  1. 概述
  2. Move语义
  3. 右值引用
  4. 强制Move语义
  5. 右值引用就是右值吗?
  6. Move语义和编译器优化
  7. Perfect Forwarding(完美转发):问题
  8. Perfect Forwarding(完美转发):解决方案
  9. 右值引用和异常
  10. Implicit Move情况
  11. 鸣谢和深入阅读

概述

右值引用是随着C++11标准被引入的一项C++特性。造成右值引用比较难于理解的地方在于:当你刚开始接触它的时候,比较难以搞清楚它存在的目的或者它将要解决什么样的问题。因此,我不会直接阐述什么是右值引用。相反,我会从将要被它解决的问题开始,然后给出是如何通过利用右值引用解决这些问题的。这样,右值引用的定义将会比较合理、自然的呈现给你。

右值引用至少将解决如下两个问题:

  1. 实现Move语义(aka. Move Semantics)
  2. Perfect forwarding(完美转发)

如果你对这些问题并不熟悉,不要担心。下面将会详细解释它们。我们先从Move语义开始。但在开始之前,我需要先提醒你C++中什么是左值(lvalues)和右值(rvalues)。想要给出一个严谨的定义是非常困难的,但是下面的解释对于目的来说已经足够了。

原始的关于左值右值的定义在早期的C是这样的:一个左值是一个可能出现在一个赋值左手边或右手边的表达式e。右值则是只能出现在一个赋值右手边的表达式。举例:

int a = 42;int b = 43;// a和b都是左值s:a = b; // okb = a; // oka = a * b; // ok// a * b 是右值:int c = a * b; // ok, 右值在赋值的右手边a * b = 42; // error, 右值在赋值的左手边

在C++中,最初这依然可用,也是对于左值和右值辨认的直觉方法。然而,随着C++和它的用户自定义类型引入了一些关于可变性(modifiability)和可转让性(assignability)的微妙变化,导致这个定义不再正确。我们不需要再深入探讨这个问题。接下来是另一份对此的定义,虽说它可能依然经不起推敲,但是可以让你用来处理右值引用:一个左值是一个能够指向内存地址的表达式,并允许我们通过&操作符来获取那块内存地址。一个右值是一个非左值的表达式。举例如下:

// 左值://int i = 42;i = 43; // ok, i是左值int* p = &i; // ok, i是左值int& foo();foo() = 42; // ok, foo()是左值int* p1 = &foo(); // ok, foo()是左值// 右值://int foobar();int j = 0;j = foobar(); // ok, foobar()是右值int* p2 = &foobar(); // error,不能从右值取址j = 42; // ok, 42是右值

如果你对严谨的右值和左值定义感兴趣,Mikael Kilpeläinen的这份ACCU文章是就这个课题一份比较好的开始。

翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述