C++右值引用和移动语义学习小结

在 C++11 之前,将一个对象移动(move)到另一个对象的通用做法只有 copy constructor 或者 copy assignment ,然后销毁原来的对象。如果这个对象的创建涉及动态内存分配的话,copy constructor 或者 copy assignment 的开销就可能比较大。

从 C++11 开始,C++ 引入了移动语义(move semantics)。由此 C++11 的 class 也多了两个特殊的成员函数 —— move constructor 和 move assignment。 引入移动语义,首先要做的第一件事就是,如何确定该用 move 还是 copy ? 为此 C++11 引入了右值引用这个概念 —— 在 C++ 里所有的右值都可以被移动。

这里又有了另一个问题:什么是右值引用、右值?相对的还有左值引用、左值? 左值与右值这两概念是从 C 语言中传承而来的。在 C 语言中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。 左值可以取到其内存地址,右值不能。左值与右值的根本区别在于能否获取内存地址。 左值引用和右值引用,其实就是左值的引用和右值的引用。他们俩都是引用,区别在于引用的数据是啥。 注意,左值引用和右值引用都是左值。

下面举几个简单的列子:

int i = 42;                 // i 是个左值,42 是个右值
int& r = i;                 // r 是个左值引用
int&& rr = i;               // 错误,不能将左值 i 绑定到右值引用 rr 上
int&& rr1 = std::move(i);    // std::move 将 i 强制转换成一个右值
int &r2 = i * 42;           // 错误: i * 42 是一个右值,不能绑定到一个左值引用
const int &r3 = i * 42;     // 可以将一个右值绑定到一个 const 的左值引用
int &&rr2 = i * 42;         // 将右值绑定到右值引用

从上面的例子可以看到,有两种引用可以绑定到右值:const 左值引用和右值引用

当传入的对象是右值且支持 move constructor 或 move assignment 时,C++ 会使用移动语义的函数。如果不支持移动语义的函数,无论传入的对象是右值还是左值,C++ 还是会使用复制语义的函数。 因为左值引用和右值引用其实都是左值, C++11 提供了一个函数 std::move 可以将一个对象强制转换成右值(rvalue)。

移动语义的出现,一方面可以让编译器在某些情况下,使用 move 而不是 copy 来提升程序性能。另一方面,让一些 move-only 的类型在语义上更加明确,如 std::unique_ptrstd::futurestd::thread

更多关于右值引用、移动语义的内容,请参考

  • C++ Primer 5th, 13.6 Moving Objects
  • Effective Mordern C++, Chapter 5 Rvalue References, Move Semantics, and Perfect Forwarding

最后,附上之前整理的电子书下载链接:C++ 学习资料整理(电子书)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Hongten

python开发_calendar

如果你用过linux,你可能知道在linux下面的有一个强大的calendar功能,即日历

1162
来自专栏码匠的流水账

聊聊storm的WindowedBolt

storm-2.0.0/storm-client/src/jvm/org/apache/storm/topology/IWindowedBolt.java

2054
来自专栏码匠的流水账

聊聊storm TridentTopology的构建

storm-core-1.2.2-sources.jar!/org/apache/storm/trident/TridentTopology.java

1703
来自专栏前端说吧

正则表达式验证汇总

一、收集1  (转自https://blog.csdn.net/jumtre/article/details/13775351)

841
来自专栏java系列博客

HibernateCallback 的用法

1072
来自专栏Albert陈凯

2018-04-17 Java的Collection集合类3分钟搞掂Set集合前言

3分钟搞掂Set集合 前言 声明,本文用的是jdk1.8 现在这篇主要讲Set集合的三个子类: HashSet集合 A:底层数据结构是哈希表(是一个元素为链...

2977
来自专栏coding

从任意长度的可迭代对象中分解元素

1036
来自专栏小樱的经验随笔

Code forces 719A Vitya in the Countryside

A. Vitya in the Countryside time limit per test:1 second memory limit per test:2...

3436
来自专栏函数式编程语言及工具

SDP(9):MongoDB-Scala - data access and modeling

    MongoDB是一种文件型数据库,对数据格式没有硬性要求,所以可以实现灵活多变的数据存储和读取。MongoDB又是一种分布式数据库,与传统关系数据库不同...

3894
来自专栏悦思悦读

Spark Tips3: 在Spark Streaming job中读取Kafka messages及其offsetRange

在Spark Streaming job中读取Kafka topic(s)中的messages时,有时我们会需要同步记录下每次读取的messages的offse...

48112

扫码关注云+社区