C++11中的右值引用及move语义编程

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构造函数,虽然现在这种编程方法没有流行,但是我相信以后这将成为另外一个媲美引用的优化运行速度的编程方法,我们拭目以待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IBatis 映射文件 sql 中大于、小于等符号转义

相信好多朋友在写配置文件的时候&#xff0c; 直接写 > 、<、>、< 编译不通过! 这些其实就是 xml 文体的特殊符号,在编写是需要转义&#xff0c;有两种方式处理&#xff0c;如下: 方法一 : 直接替换 <<>><><>&&amp;&apos…

python入侵数据库数据库_一个简单的Python访问Mysql数据库例子

2020/11/3操作记录搭建好Python的数据环境之后&#xff0c;接下来就是在Python代码中访问数据库我先在Navicat图形化界面创建一个数据库命名为pythontest&#xff0c;再在数据库中创建了一个表studentinfo有nid,nname,ngrade,nage四个字段&#xff0c;nid为主键递增。通过查询编…

r语言散点图_R语言 | 散点图入门:以声学元音图为例

R语言语言学与R语言的碰撞Xu & YangPhoneticSan学习参考Discovering Statistics Using RStatistics for Linguistics with RHow to Do Linguistics with RR in ActionAnalyzing Linguistic DataR Graphics Cookbook Recap可以使用plot( )函数进行基础的制图。调用ggplot2包…

oracle中如何创建dblink

当用户要跨本地数据库&#xff0c;访问另外一个数据库表中的数据时&#xff0c;本地数据库中必须创建了远程数据库的dblink,通过dblink本地数据库可以像访问本地数据库一样访问远程数据库表中的数据。下面讲介绍如何在本地数据库中创建dblink. 创建dblink一般有两种方式&#x…

哪里的mysql性能监控_mysql性能监控工具Innotop简介及配置

# wget http://innotop.googlecode.com/files/innotop-1.9.0.tar.gz# tar -zxvf innotop-1.9.0.tar.gz# cd innotop-1.9.0安装INNOTOP工具非常简单&#xff0c;其是由PERL写的&#xff0c;当然需要PERL环境和相关的工具包。在安装之前先要确定你的系统安装了Time::HiRes,Term::…

python能不能爬数据库_python爬取数据后不能写入到数据库中

目标&#xff1a;去爬当当网某页内容中的书籍的名称&#xff0c;链接和评论数&#xff0c;然后写入数据库中pipelins内容如下&#xff1a;import pymysqlclass DangdangPipeline(object):def process_item(self, item, spider):conn pymysql.connect(host"127.0.0.1"…

mysql创建表里主码和外码_SQL语言创建表时候怎么定义主码和外码

展开全部SQL语言创建表时候用Primary Key(属性名)定义主码&#xff0c;用Foreign Key(属性名)定义外码。主码是一种唯一关键字&#xff0c;表定62616964757a686964616fe59b9ee7ad9431333433623064义的一部分。一个表的主码可以由多个关键字共同组成&#xff0c;并且主码的列不能…

Autodesk 360 Mobile不能显示图片?

在6月21号的DevLab上&#xff0c;有一位朋友说Autodesk 360 Mobile在iPad上不能显示JPG图片预览。我当时没带iPad&#xff0c;不能测试。后天回家在Autodesk 360 Mobile 3.0试了一下&#xff0c;还真是这样。 这应该是Autodesk 360 Mobile 3.0的bug&#xff0c;不过升级到Autod…

关于std:auto_ptr

很多人听说过标准auto_ptr智能指针机制&#xff0c;但并不是每个人都天天使用它。这真是个遗憾&#xff0c;因为auto_ptr优雅地解决了C设计和编码中常见的问题&#xff0c;正确地使用它可以生成健壮的代码。本文阐述了如何正确运用auto_ptr来让你的代码更加安全——以及如何避免…

unity镜头边缘羽化_【后期修图】如何利用Ps中的自适应广角滤波器校正镜头失真?...

当用广角镜头拍摄对象时&#xff0c;透视问题通常以线条的形式出现&#xff0c;这应该是直的&#xff0c;但看起来是弯曲的和扭曲的。这通常被称为桶形失真&#xff0c;其主要发生在广角镜头中&#xff0c;因为图像的放大率越远&#xff0c;主体离镜头的光轴越远。简单来说&…

mysql查看事件任务内容_MySql事件计划任务

DROP EVENT IF EXISTS eve1;DELIMITER $$CREATE EVENT eve1 ON SCHEDULE EVERY 1 SECOND STARTS NOW() ENDS NOW()1ON COMPLETION PRESERVEDISABLEDOBEGINUPDATE testtable1 SET age age1 WHERE id 1;END$$DELIMITER ;SELECT * FROM testtable1;SELECT NOW();/*标准创建语句E…

Delphi 对象的创建(create)与释放(free/destory)

Delphi 对象的创建(create)与释放(free/destory) 1、Create参数为:nil/self/application的区别&#xff0c;最好能看到实际效果的区别 例如: My : TMy.Create(X); 其中的 X 将会成为控件 My 的 Owner 属性, 可能会不只一个控件把 X 当作 Owner. 当 X 释放时, 它会同时释放那些…

用引用返回值(转)

函数返回值时&#xff0c;要生成一个值的副本。而用引用返回值时&#xff0c;不生成值的副本。例如&#xff0c;下面的程序是有关引用返回的4种形式&#xff1a;//*********************//**   ch9_6.cpp  **//********************* #include <iostream.h> float tem…

python 串口助手 简书_python用pyserial读取串口问题解决

object is not callableError:‘bool’ object is not callable没有返回值正确代码&#xff1a;ser serial.Serial(COM7, 115200, 8, N, 1)flag ser.is_open原因&#xff1a;调用属性is_open时将其视为函数&#xff0c;写成 ser.is_open()。关于is_open的功能及用法&#xff…

mysql用binlog恢复数据_利用mysql的binlog恢复数据

MySQL Binary Log也就是常说的bin-log, ,是mysql执行改动产生的二进制日志文件,其主要作用有两个:* 数据回复* 主从数据库。用于slave端执行增删改&#xff0c;保持与master同步。1.开启binary log功能需要修改mysql的配置文件&#xff0c;本篇的实验环境是win7&#xff0c;配置…

Perl,Python,Ruby,Javascript 四种脚本语言比较

Perl 为了选择一个合适的脚本语言学习&#xff0c;今天查了不少有关Perl&#xff0c;Python&#xff0c;Ruby&#xff0c;Javascript的东西&#xff0c;可是发现各大阵营的人都在吹捧自己喜欢的语言&#xff0c;不过最没有争议的应该是Javascript现阶段还不适合用来做独立开发&…

C++中的IPv6网络程序设计

IPv4 最初是由美国国防部开发的用于网际互联&#xff08;IP&#xff09;协议&#xff0c;后来它不仅发展了TCP&#xff0c;而且还进一步发展了IPv4&#xff08;IP 协议4.0版&#xff09;。IPv4现在已经广泛应用于Internet网络中&#xff0c;同时也应用于大多数计算机系统&#…

python regex_Python 正则表达式

定义在编写处理字符串的程序或网页时&#xff0c;经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。简而言之&#xff1a;正则表达式就是记录文本规则的代码。特点:操作字符串1.更快的方式操作字符串&#xff1b;(表单校验&#xff0c;数据…

python 怎么处理json_Python是怎样处理json模块的

首先&#xff0c;了解下什么是JSON&#xff1f;JSON&#xff1a;JavaScript Object Notation 【JavaScript 对象表示法】JSON 是一种轻量级的数据交换格式&#xff0c;完全独立于任何程序语言的文本格式。一般&#xff0c;后台应用程序将响应数据封装成JSON格式返回。JSON的基本…

UEditor1.2.6.0在.net环境下使用

UEditor1.2.6.0 1.百度百科词条 2.UEditor官方网站 【CKEditorCKFinder的配置实用&#xff0c;可查看博主另一篇文章】 第一次接触UEditor还是在2011年的下半年里&#xff0c;当时由于需要找一款富文本编辑器进行新闻的网站开发&#xff0c;当时UEditor异常较多&#xff0c;就将…