详解C++移动语义std::move()
目录
1. C++move的概念
2. C++move的特点
3. 左值、右值与左值引用、右值引用
3.1 左值和右值的概念
3.2 左值引用和右值引用
4. std::move详解
4.1 std::move简介
4.2 std::move详解
4.3 std::move实现:
4.4 std::move的优点
4.5 std::move的使用
参考:
https://blog.csdn.net/s11show_163/article/details/114296006
https://blog.csdn.net/daaikuaichuan/article/details/88371948
https://zhuanlan.zhihu.com/p/94588204
https://www.cnblogs.com/SZxiaochun/p/8017475.html
https://www.cnblogs.com/yoyo-sincerely/p/8658075.html
左值引用与右值引用,以及为什么右值引用本身是左值的问题详见:https://www.cnblogs.com/char-cheng/p/11026936.html
1. C++move的概念
一句话概括std::move ———— std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
2. C++move的特点
- std::move函数可以以非常简单的方式将左值引用转换为右值引用。(左值、左值引用、右值、右值引用 参见:http://www.cnblogs.com/SZxiaochun/p/8017475.html)
- 通过std::move,可以避免不必要的拷贝操作。
- std::move是为性能而生。
- std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
- 如string类在赋值或者拷贝构造函数中会声明char数组来存放数据,然后把原string中的 char 数组被析构函数释放,如果a是一个临时变量,则上面的拷贝,析构就是多余的,完全可以把临时变量a中的数据直接 “转移” 到新的变量下面即可。
3. 左值、右值与左值引用、右值引用
右值引用(及其支持的Move语意和完美转发)是C++0x加入的最重大语言特性之一。从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题。从语言本身讲,它健全了C++中的引用类型在左值右值方面的缺陷。从库设计者的角度讲,它给库设计者又带来了一把利器。从库使用者的角度讲,不动一兵一卒便可以获得“免费的”效率提升。
3.1 左值和右值的概念
- 左值是可以放在赋值号左边可以被赋值的值;左值必须要在内存中有实体;
- 右值当在赋值号右边取出值赋给其他变量的值;右值可以在内存也可以在CPU寄存器。
- 一个对象被用作右值时,使用的是它的内容(值),被当作左值时,使用的是它的地址。
- 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 。
- 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字。
int a;
int b;a = 3;
b = 4;
a = b;
b = a;// 以下写法不合法。
3 = a;
a + b = 4;
3.2 左值引用和右值引用
引用是C++语法做的优化,引用的本质还是靠指针来实现的。引用相当于变量的别名。引用可以改变指针的指向,还可以改变指针所指向的值。
左值引用:type &引用名 = 左值表达式;就是对左值的引用 就是给左值取别名
右值引用:type &&引用名 = 右值表达式;就是对右值的引用 就是给右值取别名
int a=10; //a 是左值
double b=1.3; //b 是左值
//左值引用
int & Ta=a; //引用左值 故 是一个左值引用
double & Tb=b; //引用左值 故是一个左值引用
再比如:
int a = 100;
int&& b = 100;//右值引用
int& c = b; //正确,b为左值
int& d = 100; //错误
4. std::move详解
4.1 std::move简介
在C++11中,标准库在中提供了一个有用的函数std::move,std::move并不能移动任何东西,它唯一的功能是将一个左值引用强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{std::string str = "Hello";std::vector<std::string> v;//调用常规的拷贝构造函数,新建字符数组,拷贝数据v.push_back(str);std::cout << "After copy, str is \"" << str << "\"\n"; //str输出为"Hello"//调用移动构造函数,掏空str,掏空后,最好不要使用strv.push_back(std::move(str));std::cout << "After move, str is \"" << str << "\"\n"; //str输出为空std::cout << "The contents of the vector are \"" << v[0]<< "\", \"" << v[1] << "\"\n";//v[0]、v[1]都为"Hello"
}
输出
After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"
4.2 std::move详解
std::move 的函数原型定义:
template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{return static_cast<typename remove_reference<T>::type &&>(t);
}
首先,函数参数T&&是一个指向模板类型参数的右值引用,通过引用折叠,此参数可以与任何类型的实参匹配(可以传递左值或右值,这是std::move主要使用的两种场景)。关于引用折叠如下:
所有右值引用折叠到右值引用上仍然是一个右值引用。(A&& && 变成 A&&) 。
所有的其他引用类型之间的折叠都将变成左值引用。 (A& & 变成 A&; A& && 变成 A&; A&& & 变成 A&)。
简单来说,右值经过T&&传递类型保持不变还是右值,而左值经过T&&变为普通的左值引用。
//原始的,最通用的版本
template <typename T> struct remove_reference{typedef T type; //定义T的类型别名为type
};//部分版本特例化,将用于左值引用和右值引用
template <class T> struct remove_reference<T&> //左值引用
{ typedef T type; }template <class T> struct remove_reference<T&&> //右值引用
{ typedef T type; } //举例如下,下列定义的a、b、c三个变量都是int类型
int i;
remove_refrence<decltype(42)>::type a; //使用原版本,
remove_refrence<decltype(i)>::type b; //左值引用特例版本
remove_refrence<decltype(std::move(i))>::type b; //右值引用特例版本
4.3 std::move实现:
1. 首先,通过右值引用传递模板实现,利用引用折叠原理将右值经过T&&传递类型保持不变还是右值,而左值经过T&&变为普通的左值引用,以保证模板可以传递任意实参,且保持类型不变。(cpr:先能够把参数类型全都接收)
2. 然后我们通过static_cast<>进行强制类型转换返回T&&右值引用,而static_cast之所以能使用类型转换,是通过remove_refrence::type模板移除T&&,T&的引用,获取具体类型T(模板偏特化)。(cpr:再把接收的参数的原引用抹除强转成右引)
4.4 std::move的优点
std::move语句可以将左值变为右值而避免拷贝构造。
std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝。
4.5 std::move的使用
比如向vector中插入新元素。
int a = 1;
vector<int> vec;
vec.push_back(move(a));
详解C++移动语义std::move()相关推荐
- 百度AI开发者大会百度大脑论坛:详解“多模态深度语义理解”
7月4日召开的百度AI开发者大会(Baidu Create 2018)上,百度高级副总裁.AI技术平台体系(AIG)总负责人王海峰发布百度大脑3.0,并指出,百度大脑3.0的核心是"多模态深 ...
- UNIX(多线程):19---Future 类型详解
Future 类型详解 本文主要介绍 std::future,std::shared_future 以及 std::future_error,另外还会介绍 <future> 头文件中的 s ...
- 主成分分析(PCA)——matlab程序及函数详解
参考来源: http://www.cnblogs.com/Hand-Head/articles/5156435.html http://www.matlabsky.com/thread-11751-1 ...
- c++ std::move详解
c++ std::move详解 在移动构造中的时候,移动拷贝其实就是把原来参数对象的指针地址给到了构造的对象,再把原先对象的指针置为NULL,这样内存就不会被原来函数给析构了.对于实体的对象执行的其实 ...
- std::move作用详解
C++11右值引用和std::move语句实例解析 关键字:C++11,右值引用,rvalue,std::move,VS 2015 OS:Windows 10 右值引用(及其支持的Move语意和完美转 ...
- C++11 并发指南四(future 详解二 std::packaged_task 介绍)
上一讲<C++11 并发指南四(<future> 详解一 std::promise 介绍)>主要介绍了 <future> 头文件中的 std::promise 类, ...
- C++11 并发指南四(future 详解一 std::promise 介绍)
前面两讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread 和 std::m ...
- C++11 并发指南------std::thread 详解
参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Int ...
- C++11 并发指南三(std::mutex 详解)
上一篇<C++11 并发指南二(std::thread 详解)>中主要讲到了 std::thread 的一些用法,并给出了两个小例子,本文将介绍 std::mutex 的用法. Mutex ...
最新文章
- 【直播】林锦弘:CV赛事高分经验分享
- 没有这 29 款插件的 Chrome 是没有灵魂的!
- 初识FPGA(一)(初步介绍FPGA)
- Dropout和网络结构实现数据增广带来的不同影响分析
- 一款WP小游戏代码分享
- 梯度与梯度下降法详解
- 四大触点,教你从“用户视角”构建数据分析体系
- prettytensor 的使用
- 中文路径读取乱码,json乱码
- Qt的project文件的设置相关
- ipad无法加入网络怎么办?
- 中国企业软件25年到底有几次颠覆
- OpenCV实践(4)- 叠加两幅图片
- 在直播软件搭建中,如何基于rtmp实现视频直播?
- WPF 使用 Direct2D1 画图入门
- ABAP tRFC和qRFC
- atom 编辑器html,Atom编辑器配置
- html5定义一个变量,JavaScript 变量
- windows下测试磁盘读写(HD Tune)
- 元胞自动机 C实现 + OpenCV界面