std::move的原理与实现,右值引用的深入理解
这次我真的懂了。。。。
首先C++11引入了右值引用 &&
‘&&’这个要连起来看,是一个整体,C++多了一个关键字而已。
不是引用的引用。是船新的一种语法。那有什么用呢?
额,参数的类型又多了一种!
void fun(int T)
void fun(int& T)
void fun(int && T)
void fun(int* t)
之前的参数,值传递,引用,指针。现在呢?多了一个叫 “右值引用”的玩意,多了一种参数类型的选择。仅此而已。
那他们号称的右值引用速度快,代价小呢?
额,这个需要库作者自己去实现的,跟C++语言本身无关。
举两个例子
void fun(int & t)
{
t= 2;
}
void fun(int && t)
{
cout<<"int &&"<<endl;
int x = t;
x++;
x--;
}
这个右值引用的fun函数就更复杂了嘛,没有说一定要简单啊,完全由库作者决定的。
当然,现在的库作者对右值引用的函数往往做了内存转移的操作(尤其是移动构造函数与移动赋值函数)
class A
{
A(int num)
{
p = new int(num);
}
A(A& a)
{
p = new int(*a.p);
}
A(A&& a)
{
p = a.p;
a.p = nullptr;
}
~A()
{
delete p;
}
private:
int * p=nullptr;
};
如上,对于右值引用构造函数,仅仅是转移了内存,并让被转移的指针置空。当然,这个右值引用构造函数具体的实现还是由库作者决定的。
另外,如果没有右值引用构造函数,会自动调用拷贝构造函数。
这里说到了转移,嗯,翻译下就是move。move这个函数看上去是专门转移内存的。实际上是错误的。。
move仅仅是进行了一个 右值引用 的强制转换。
对于强制转换,你可能会写
template<typename T>
T && make_move(T&& t) //当然真正的是std::move,我这里取名实现类似的move。make_move跟make_love没有关系哈,纯粹的偶然。。
{
return static_cast<T&&>(t);
}
额,这是啥,T &&转换成T&& ,看上去啥都没做嘛。
首先:对于make_move(T&& t)中的 t,说明make_move的函数参数是右值引用,但不代表t是右值引用。t可能是左值。额,越来越头大了。
想起了“书越读越厚,然后越读越薄”。其实我自己对这个的理解过程也超过了2年多,这次真的搞懂了!!
上例子缓缓
int x =10;
make_move(x) //此时x是左值,什么叫左值,就是可以取地址的变量。&x有意义的变量。
make_move(20) //20是真正的右值。
看上去这个时候make_move体现出了意义,把t强转成右值引用了。
但读过 模板类型推倒、auto推导 后,我们知道,左值(或引用)的强制右值转换返回是个左值引用。简单的如下:

于是,经过make_move函数后返回的是int & 而不是int &&。
那怎么才能得到真正的int && 呢。需要加上traits。
template<typename T>
typename remove_reference<T>::type && make_move(T&& t)
{
using Rtype = typename remove_reference<T>::type &&;
return static_cast<Rtype>(t);
}
typename 是为了告诉编译器type是一个类型,这个在stl很常见。
举个例子
struct A
{
typedef unsigned size_t;
static size_t value;
}
我们访问value 使用A::value
我们访问size_t 使用A::size_t 那么size_t到底是值还是类型,编译器不明白。
所以我们会用 typename A::size_t ; (typename 翻译类型名字,就是表明该变量是个类型)
remove_reference<T>::type 就是去掉T的引用后的类型,再加上&&
就是真的T的右值引用了。
如你所见,这个也基本是std::move干的事。因此move并没有转移内存还是啥的,甚至没有转移的语义。只是一种类型的强制转换。所以如果命名为rvalue_cast,我也能早点懂得。
std::vector<std::string> ve;
std::string str="msg";
ve.push_back(str);
ve.push_back(std::move(str)); //内部实现可能是这样子的
void push_back(str)
{
T temp (str); //调用值拷贝构造
__insert(temp);
}
ve.push_back(std::move(str));
{
T temp (t) ; //调用右值拷贝构造
__insert(temp);
}
确实会比ve.push_back(str)快一点点,std::string的右值拷贝构造直接转移了内存。
最终看起来像是move的功劳,也实现了转移的语义。
但实际上是std::string的右值拷贝构造直接转移了内存。当然感谢move,但str真的从左值变成了右值引用。
the end
std::move的原理与实现,右值引用的深入理解的更多相关文章
- 右值引用和std::move函数(c++11)
1.对象移动 1)C++11新标准中的一个最主要的特性就是移动而非拷贝对象的能力 2)优势: 在某些情况下,从旧内存拷贝到新内存是不必要的,此时对对象进行移动而非拷贝可以提升性能 有些类如IO类或un ...
- 详解C++右值引用
C++0x标准出来很长时间了,引入了很多牛逼的特性[1].其中一个便是右值引用,Thomas Becker的文章[2]很全面的介绍了这个特性,读后有如醍醐灌顶,翻译在此以便深入理解. 目录 概述 mo ...
- c++11的右值引用、移动语义
对于c++11来说移动语义是一个重要的概念,一直以来我对这个概念都似懂非懂.最近翻翻资料感觉突然开窍,因此记下.其实搞懂之后就会发现这个概念很简单,并无什么高深的地方. 先说说右值引用.右值一般指的是 ...
- 【转】C++11 标准新特性: 右值引用与转移语义
VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...
- [转载] C++11中的右值引用
C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...
- C++11中的右值引用
原文出处:http://kuring.me/post/cpp11_right_reference May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移 ...
- C++11 标准新特性: 右值引用与转移语义
文章出处:https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ 新特性的目的 右值引用 (Rvalue Referene) ...
- C++11 右值引用和转移语义
新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...
- C++11 的右值引用
作者:Tinro链接:https://www.zhihu.com/question/22111546/answer/30801982来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
随机推荐
- MapReduce 运行全过程解析
关注公众号,大家可以在公众号后台回复“博客园”,免费获得作者 Java 知识体系/面试必看资料. 前言 前面我们讲了 MapReduce 的编程模型,我们知道他主要分成两大阶段来完成一项任务,一是 m ...
- Spring注解浅入浅出——不吹牛逼不装逼
Spring注解浅入浅出——不吹牛逼不装逼 前情提要 上文书咱们说了<Spring浅入浅出>,对Spring的核心思想看过上篇的朋友应该已经掌握了,此篇用上篇铺垫,引入注解,继续深入学习. ...
- java并发编程(十七)----(线程池)java线程池架构和原理
前面我们简单介绍了线程池的使用,但是对于其如何运行我们还不清楚,Executors为我们提供了简单的线程工厂类,但是我们知道ThreadPoolExecutor是线程池的具体实现类.我们先从他开始分析 ...
- 微信公众号发送消息给用户 php
1.微信公众号 这里得话 一开始先去看了 微信公众号的接口 发现网页授权需要时认证的服务号,一开始想的是那去申请一个认证的服务号岂不是很费事,然后网上搜了搜,发现了还有微信公众号个人测试号这个东西,所 ...
- 如何使用dmidecode命令查看硬件信息
引言 当我们需要获取机器硬件信息时,可使用linux系统自带的dmidecode工具进行查询. dmidecode命令通过读取系统DMI表,显示服务器硬件和BIOS信息.除了可使用dmidecode查 ...
- java Timer工具类实现定时器任务
第一 schedule 方法 三个参数 按照顺序 (执行的任务方法,开始执行时间,多少时间后循环去执行) 代码可用 public class TestScheedule { public stati ...
- DedeCMS 5.7 sp1远程文件包含漏洞(CVE-2015-4553)
DedeCMS 5.7 sp1远程文件包含漏洞(CVE-2015-4553) 一.漏洞描述 该漏洞在/install/index.php(index.php.bak)文件中,漏洞起因是$$符号使用不当 ...
- C语言之左移和右移运算符
C语言中的左移和右移运算符移位后的结果老是忘记,最近在刷有关位操作的题目,正好整理下: 1. 左移运算符(<<) 左移运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指 ...
- ubuntu-18.10 虚拟机 配置网络环境
查询主机系统ip 使用virtualbox 设置网络模式为桥接模式 设置静态 ip 与网关 关闭防火墙 sudo ufw disable
- 洛谷 P1177 【模板】快速排序
这道题用传统快排(如下所示)的结果就是最后三个点TLE: void swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } void ...