C++0x中加入了右值引用,和move函数。右值引用出现之前我们只能用const引用来关联临时对象(右值)(造孽的VS可以用非const引用关联临时对象,请忽略VS),所以我们不能修临时对象的内容,右值引用的出现就让我们可以取得临时对象的控制权,终于可以修改临时对象了!而且书上说配合move函数,可以大大提高现有C++的效率。那么是怎样提高它的效率的呢?看段代码先!

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{std::string str = "Hello";std::vector<std::string> v;// uses the push_back(const T&) overload, which means // we'll incur the cost of copying str
    v.push_back(str);std::cout << "After copy, str is \"" << str << "\"\n";// uses the rvalue reference push_back(T&&) overload, // which means no strings will copied; instead, the contents// of str will be moved into the vector.  This is less// expensive, but also means str might now be empty.
    v.push_back(std::move(str));std::cout << "After move, str is \"" << str << "\"\n";std::cout << "The contents of the vector are \"" << v[0]<< "\", \"" << v[1] << "\"\n";
}

Output:

After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"

看完大概明白一点儿了,加上move之后,str对象里面的内容被"移动"到新的对象中并插入到数组之中了,同时str被清空了。这样一来省去了对象拷贝的过程。所以说在str对象不再使用的情况下,这种做法的效率更高一些!但问题是str的内容在什么地方被移走的呢?move函数到底是干啥的?扣一下stl源码吧,下面是move模板的源码:

// TEMPLATE FUNCTION movetemplate<class _Ty> inlinetypename tr1::_Remove_reference<_Ty>::_Type&&move(_Ty&& _Arg){    // forward _Arg as movablereturn ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);}

好吧,看过了这段,可能有人又迷惑了,不是说有名左指变量不能绑定到右值引用上面么?为什么move函数的参数是右值引用却可以接受左值变量作为参数?难道STL错了么?事实上,C++0x在引入右值引用的时候对函数模板自动推导也加入了新的规则,简单的说,像例子中的这种情况,模板参数是_Ty而函数的参数是_Ty&&(右值引用),同时_Arg是string的左值对象的情况下,会触发一个特殊规则,_Ty会推导成string&,也就是说此事推导出来的函数与move<string&>一致。那么move(_Ty&& _Arg) 得到的应该是move(string& && _Arg)这个时候根据引用折叠原则,会变成这个样子move(string& _Arg)。详细的描述参见白云飘飘翻译的vc技术文档(http://www.cppblog.com/kesalin/archive/2009/06/05/86851.html)。函数的返回值嘛,就好说了,就是返回所持有类型的右值引用了。所以,move函数的作用很简单,不管你给什么参数,都返回对应类型的右值引用!那么,上面例子中str的不是在move函数中被移走的。综上,我们猜测str内容肯定是在构造新对象的过程中被新对象偷走的,也就是在string的参数为右值引用的构造函数中被偷走的!翻看string的源码(来自VS实现的STL),果然如此啊!如下:

        basic_string(_Myt&& _Right): _Mybase(_STD forward<_Alloc>(_Right._Alval)){    // construct by moving _Right
        _Tidy();assign(_STD forward<_Myt>(_Right));}
_Myt& assign(_Myt&& _Right){    // assign by moving _Rightif (this == &_Right);else if (get_allocator() != _Right.get_allocator()&& this->_BUF_SIZE <= _Right._Myres)*this = _Right;else{    // not same, clear this and steal from _Right_Tidy(true);if (_Right._Myres < this->_BUF_SIZE)_Traits::move(this->_Bx._Buf, _Right._Bx._Buf,_Right._Mysize + 1);else{    // copy pointerthis->_Bx._Ptr = _Right._Bx._Ptr;_Right._Bx._Ptr = 0;}this->_Mysize = _Right._Mysize;this->_Myres = _Right._Myres;_Right._Tidy();}return (*this);}

所以,我们知道了,C++0x在STL模板库中加入了参数为右值引用的构造函数,用于把参数所关联对象中的数据移动到新对象当中,避免了深度拷贝,增加了效率。再详细翻看源码,可以发现除了构造函数,operator=也重载了一个参数为右值引用的函数,用途和构造函数类似。所以我们自定义中的类也应该增加参数为右值引用的构造函数和重载赋值运算符!原因是啥,看例子!

未定义参数为右值引用的构造函数:

#include <iostream>
#include <utility>
#include <vector>
#include <string>using namespace std;class MyPoint{
public:MyPoint():comment(""), x(0), y(0){}MyPoint(const MyPoint& p):comment(p.comment),x(p.x),y(p.y) {}    //MyPoint(MyPoint&& p)//    :comment(move(p.comment)), x(p.x), y(p.y)//{//    p.x = 0;//    p.y = 0;//}string toString(){char buf[100];sprintf(buf, "%s: %d %d", comment.c_str(), x, y);return buf;}string comment;int x;int y;};int main()
{MyPoint p;p.comment = "First point";p.x = 9;p.y = 7;vector<MyPoint> v;v.push_back(p);cout << "After copy, str is \"" << p.toString() << "\"\n";v.push_back(move(p));cout << "After move, str is \"" << p.toString() << "\"\n";cout << "The contents of the vector are \"" << v[0].toString()<< "\", \"" << v[1].toString() << "\"\n";cin.get();
}

结果:

After copy, str is "First point: 9 7"
After move, str is "First point: 9 7"
The contents of the vector are "First point: 9 7", "First point: 9 7"

定义了参数为右值引用的构造函数之后:

After copy, str is "First point: 9 7"
After move, str is ": 0 0"
The contents of the vector are "First point: 9 7", "First point: 9 7"

综上所述,C++0x中的move语义编程,不仅仅是在应用的时候使用参数中加上move,对于自定义类需要增加参数为右值引用的构造函数和赋值运算符,这种构造函数我们称为move构造函数!公司里面的c++标准已经更新,要求在定义copy构造函数的同时定义move构造函数,虽然现在这种编程方法没有流行,但是我相信以后这将成为另外一个媲美引用的优化运行速度的编程方法,我们拭目以待!

C++11中的右值引用及move语义编程相关推荐

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

    C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream>     #include & ...

  2. C++11中的右值引用(对比左值引用和常引用)、移动构造函数和引用标识符

    Hello!各位同学们大家好!逗比老师最近说起来还是挺尴尬的,为什么这么说呢?因为以前我对自己的C++水平还是相当自信的,经常以"精通"来自我评价.但是最近发现自己好像对C++11 ...

  3. 右值引用和move语义?

    右值引用和move语义 转移左值 函数std::move 转移左值 有时候,我们可能想转移左值,也就是说,有时候我们想让编译器把左值当作右值对待,以便能使用转移构造函数,即便这有点不安全.出于这个目的 ...

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

    http://www.cnblogs.com/yanqi0124/p/4723698.html 在C++98中有左值和右值的概念,不过这两个概念对于很多程序员并不关心,因为不知道这两个概念照样可以写出 ...

  5. 右值引用与move语义

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

  6. C++11新特性 右值引用与移动语义

    右值引用作用是可以减少内存拷贝次数,从而优化性能. 首先,什么是右值?右值是一个与左值相区分的概念.左值是:既能出现在等号左边也能出现在等号右边的变量或表达式,比如int a = 5,那么a就是一个左 ...

  7. 深入理解右值引用,move语义和完美转发

    move语义 最原始的左值和右值定义可以追溯到C语言时代,左值是可以出现在赋值符的左边和右边,然而右值只能出现在赋值符的右边.在C 里,这种方法作为初步判断左值或右值还是可以的,但不只是那么准确了.你 ...

  8. [C++11] 右值引用和移动语义

    c++11引入了右值引用和移动语义,通过避免无谓的复制,以提高程序的执行效率. 1.左值与右值 c++中的数值必属于左值或右值之一,通常有以下方法进行区分: 左值:在赋值语句左侧,右值:在赋值语句右侧 ...

  9. C++11右值引用、移动语义、完美转发详解

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

最新文章

  1. mke2fs和mkfs命令使用
  2. c++ vector用另一个vector初始化
  3. 多选框实现全选_Angular1.x-checkbox-全选amp;单选amp;多选
  4. c语言设置bufsiz大小,c语言缓冲区有关问题及c++中的this指针
  5. 会说话的狗狗本电脑版_「电脑知识」硬件狗狗专业电脑硬件检测跑分工具免安装单文件版|电脑硬件|电脑|显卡|狗狗|操作系统...
  6. php常用的的字符串转换
  7. 机器学习总结(一):线性回归、岭回归、Lasso回归
  8. 字符串hash(类似于进制的hash)
  9. 【Django 2021年最新版教程9】数据库查询操作
  10. 1.2 JAVA多线程实现
  11. 200与mcgs485实例 smart_SMAART200与MCGS-工业支持中心-西门子中国
  12. 微信小程序UI框架记录
  13. linux修复windows,Linux十大妙用:充当Windows修复工具
  14. HealthKit框架参考
  15. 间隔十年重新更新微博
  16. idea 设置编辑器 table 全部显示
  17. PHP 版 微信小程序商城 源码和搭建
  18. 支付宝沙箱开启以及配置
  19. 文档模式:标准模式、混杂模式
  20. 错误解决:failed calling webhook “dec-autonomy.xxx.io“: failed to call webhook:post

热门文章

  1. .net 转义包含转义的字符串
  2. raid5 合适 多少块硬盘_raid1 raid2 raid5 raid6 raid10如何选择使用?各需要几块硬盘?...
  3. java date转sql date_java.util.Date和java.sql.Date转换(转)
  4. java数组排序源码_Java 数组工具类排序,最大值最小值等
  5. 声速的测量的实验原理和应用_创想智控:光学三角测量系统的测量原理与应用...
  6. spring初始化bean时执行某些方法完成特定的初始化操作
  7. Python学习之==文件操作
  8. JS取消浏览器文本选中的方法
  9. 优秀的Android资源
  10. 将10进制整数转换成16进制整数输出