这次我真的懂了。。。。

首先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. kali Metasploit 连接 Postgresql 默认密码

    使用 metasploit 时, 1. 启动 postgresql service postgresql start 2. 自行测试 postgresql 是否安装成功 根据需要,自行 修改 post ...

  2. 【Java例题】3.5 级数之和

    5. 计算级数之和: y=3*1!/1-3^2*2!/2^2+3^3*3!/3^3-...+ (-1)^(n-1)*3^n*n!/n^n. 这里的"^"表示乘方,"!&q ...

  3. Mybatis获取代理对象

    mybatis-config.xml里标签可以放置多个environment,这里可以切换test和develop数据源 databaseIdProvider提供多种数据库,在xml映射文件里选择da ...

  4. Scala类和对象(二)

    1. 类和属性 1.1 如何控制构造函数字段的可见性 在Scala中: 如果一个字段被声明为var, Scala会为该字段生成getter和setter方法. 如果字段是val, Scala只生成ge ...

  5. Myeclipse8.5上基于JAX-WS开发WebService

    1.JAX-WS介绍 JAX-WS规范是一组XML web services的JAVA API. 2.开发步骤 基于JAX-WS的WebService开发步骤如下: 2.1 新建一个Web Servi ...

  6. Spring Boot Security Oauth2之客户端模式及密码模式实现

    Spring Boot Security Oauth2之客户端模式及密码模式实现 示例主要内容 1.多认证模式(密码模式.客户端模式) 2.token存到redis支持 3.资源保护 4.密码模式用户 ...

  7. Android 框架揭秘 --读书笔记

    Android 框架揭秘 Insied the Android Framework

  8. 【win10主机】访问virtualbox上【32位winXP系统虚拟机】上启动的项目

    win10上创建虚拟网卡: 1,右键此电脑点击管理——设备管理器——网络适配器: 2,点左上角菜单栏的 操作——添加过时硬件: 3,点下一步 4,点安装我手动从列表选择的硬件(高级)M 5,点网络适配 ...

  9. FastStone Capture(FSCapture) 注册码

    FastStone Capture 是一款极好用的图像浏览.编辑和截屏工具,支持 BMP.JPG.JPEG.GIF.PNG.TIFF.WMF.ICO 和 TGA 在内的主流图片格式,其独有的光滑和毛刺 ...

  10. mysql datetime timestamp区别

    timestamp 支持数据库级UTC 时区 datetime 不支持  timestamp占4个字节 datetime占8个字节 timestamp所能存储的时间范围为:'1970-01-01 00 ...