这次我真的懂了。。。。

首先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的原理与实现,右值引用的深入理解的更多相关文章

  1. 右值引用和std::move函数(c++11)

    1.对象移动 1)C++11新标准中的一个最主要的特性就是移动而非拷贝对象的能力 2)优势: 在某些情况下,从旧内存拷贝到新内存是不必要的,此时对对象进行移动而非拷贝可以提升性能 有些类如IO类或un ...

  2. 详解C++右值引用

    C++0x标准出来很长时间了,引入了很多牛逼的特性[1].其中一个便是右值引用,Thomas Becker的文章[2]很全面的介绍了这个特性,读后有如醍醐灌顶,翻译在此以便深入理解. 目录 概述 mo ...

  3. c++11的右值引用、移动语义

    对于c++11来说移动语义是一个重要的概念,一直以来我对这个概念都似懂非懂.最近翻翻资料感觉突然开窍,因此记下.其实搞懂之后就会发现这个概念很简单,并无什么高深的地方. 先说说右值引用.右值一般指的是 ...

  4. 【转】C++11 标准新特性: 右值引用与转移语义

    VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...

  5. [转载] C++11中的右值引用

    C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...

  6. C++11中的右值引用

    原文出处:http://kuring.me/post/cpp11_right_reference May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移 ...

  7. C++11 标准新特性: 右值引用与转移语义

    文章出处:https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ 新特性的目的 右值引用 (Rvalue Referene) ...

  8. C++11 右值引用和转移语义

    新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...

  9. C++11 的右值引用

    作者:Tinro链接:https://www.zhihu.com/question/22111546/answer/30801982来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

随机推荐

  1. 五、Python基础(2)

    五,Python基础(2) 1.数据类型基础 (一)什么是数据类型? 用于区分变量值的不同类型. (二)为何对数据分类? 针对不同状态就应该用不同类型的数据去标识. (三)数据类型分类 1.数字类型 ...

  2. Vue2.0仿饿了么webapp单页面应用

    Vue2.0仿饿了么webapp单页面应用 声明: 代码源于 黄轶老师在慕课网上的教学视频,我自己用vue2.0重写了该项目,喜欢的同学可以去支持老师的课程:http://coding.imooc.c ...

  3. 使用Junit测试一个 spring静态工厂实例化bean 的例子,所有代码都没有问题,但是出现java.lang.IllegalArgumentException异常

    使用Junit测试一个spring静态工厂实例化bean的例子,所有代码都没有问题,但是出现 java.lang.IllegalArgumentException 异常, 如下图所示: 开始以为是代码 ...

  4. Linux - 查看端口的占用情况、找出并杀死占用进程的方法

    目录 1 lsof查看端口的占用情况 1.1 命令使用示例 1.2 查看某一端口的占用情况 1.3 杀死某个端口的所有进程 2 netstat查看端口占用情况 2.1 命令使用示例 2.2 查看占用某 ...

  5. Netty学习(四)-TCP粘包和拆包

    我们都知道TCP是基于字节流的传输协议.那么数据在通信层传播其实就像河水一样并没有明显的分界线,而数据具体表示什么意思什么地方有句号什么地方有分号这个对于TCP底层来说并不清楚.应用层向TCP层发送用 ...

  6. U盘重装MacOS-Sierra系统

    Mac系统重新安装两种方法: 1.在线远程重装. 2.制作启动U盘进行重装. 理论上第一种比较简单,但是会比较耗时,实际操作中,由于网上下载的系统版本低于我现在MacOS的版本,导致无法安装,因此只能 ...

  7. CentOS7.x 搭建 GitLab 教程

    今天闲来无事,想起之前买了一个阿里云 ECS,一直闲置着没用,一时兴起就想搭个自己的 GitLab 玩玩,GitLab 官网也提供了安装教程,很简单,照着步骤一步步基本没什么问题,可能安装的过程中有一 ...

  8. Netty基础系列(5) --零拷贝彻底分析

    前言 上一节(堆外内存与零拷贝)当中我们从jvm堆内存的视角解释了一波零拷贝原理,但是仅仅这样还是不够的. 为了彻底搞懂零拷贝,我们趁热打铁,接着上一节来继续讲解零拷贝的底层原理. 感受一下NIO的速 ...

  9. RN 性能优化

    按需加载: 导出模块使用属性getter动态require 使用Import语句导入模块,会自动执行所加载的模块.如果你有一个公共组件供业务方使用,例如:common.js import A from ...

  10. MySQL数据库的安装和配置

    MySQL数据库介绍 什么是数据库DB? DB的全称是database,即数据库的意思.数据库实际上就是一个文件集合,是一个存储数据的仓库,数据库是按照特定的格式把数据存储起来,用户可以对存储的数据进 ...