C++11:右值引用、移动构造函数和emplace_back

2020年7月22日 周三 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】


C++11的新特性不止右值引用、移动构造函数和emplace_back这些,之所以放在一起讲,是因为它们之间存在一定的联系。


1. 右值引用

1.1 右值引用的作用

关于右值引用的作用(或者说为什么引入右值引用),百度知道上有一个回答我觉得解释的特别好,在此分享给大家:

右值引用是C++11中最重要的新特性之一,它解决了C++中大量的历史遗留问题,使C++标准库的实现在多种场景下消除了不必要的额外开销(如std::vector, std::string),也使得另外一些标准库(如std::unique_ptr,std::function)成为可能。即使你并不直接使用右值引用,也可以通过标准库,间接从这一新特性中受益。

为了更好的理解标准库结合右值引用带来的优化,我们有必要了解一下右值引用的重大意义。
右值引用的意义通常解释为两大作用:移动语义和完美转发。本文主要讨论移动语义。

作用之一:移动语义

移动语义,简单来说解决的是各种情形下对象的资源所有权转移的问题。而在C++11之前,移动语义的缺失是C++饱受诟病的问题之一。

举个栗子。
问题一:如何将大象放入冰箱?
答案是众所周知的。首先你需要有一台特殊的冰箱,这台冰箱是为了装下大象而制造的。你打开冰箱门,将大象放入冰箱,然后关上冰箱门。

问题二:如何将大象从一台冰箱转移到另一台冰箱?
普通解答:打开冰箱门,取出大象,关上冰箱门,打开另一台冰箱门,放进大象,关上冰箱门。
2B解答:在第二个冰箱中启动量子复制系统,克隆一只完全相同的大象,然后启动高能激光将第一个冰箱内的大象气化消失。

等等,这个2B解答听起来很耳熟,这不就是C++中要移动一个对象时所做的事情吗?

“移动”,这是一个三岁小孩都明白的概念。将大象(资源)从一台冰箱(对象)移动到另一台冰箱,这个行为是如此自然,没有任何人会采用先复制大象,再销毁大象这样匪夷所思的方法。C++通过拷贝构造函数和拷贝赋值操作符为类设计了拷贝/复制的概念,但为了实现对资源的移动操作,调用者必须使用先复制、再析构的方式。否则,就需要自己实现移动资源的接口。

为了实现移动语义,首先需要解决的问题是,如何标识对象的资源是可以被移动的呢?这种机制必须以一种最低开销的方式实现,并且对所有的类都有效。C++的设计者们注意到,大多数情况下,右值所包含的对象都是可以安全的被移动的。因此引入右值引用来解决移动语义问题。(这里是我的个人理解)

右值(相对应的还有左值)是从C语言设计时就有的概念,但因为其如此基础,也是一个最常被忽略的概念。不严格的来说,左值对应变量的存储位置,而右值对应变量的值本身。C++中右值可以被赋值给左值或者绑定到引用。类的右值是一个临时对象,如果没有被绑定到引用,在表达式结束时就会被废弃。于是我们可以在右值被废弃之前,移走它的资源进行废物利用,从而避免无意义的复制。被移走资源的右值在废弃时已经成为空壳,析构的开销也会降低。

右值中的数据可以被安全移走这一特性使得右值被用来表达移动语义。以同类型的右值构造对象时,需要以引用形式传入参数。右值引用顾名思义专门用来引用右值,左值引用和右值引用可以被分别重载,这样确保左值和右值分别调用到拷贝和移动的两种语义实现。对于左值,如果我们明确放弃对其资源的所有权,则可以通过std::move()来将其转为右值引用。std::move()实际上是static_cast<T&&>()的简单封装。

1.2 右值引用底层实现

int &&i = 1;

上面这句代码等价于

int temp = 1;
int &i = temp;

i 存储的实际是临时对象 temp 的地址(也就是对临时对象的一种引用)。


2. 移动构造函数

移动构造函数类似于拷贝构造函数,第一参数是该类类型的一个引用,但这个引用参数在移动构造函数中是一个右值引用。

与拷贝构造函数不同,移动构造函数不分配新内存,它接管内存并把对象中的指针都置为nullptr。最终,移后源对象会被销毁,意味着将在其上运行析构函数。

举个栗子:

#include<iostream>
#include<vector>
using namespace std;
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值