C++11的更新内容--auto--右值引用和移动构造--1114
1 初始化相关
1.1 {}初始化
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自 定义的类型。
struct Point
{int _x;int _y;
};
class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){cout << "Date(int year, int month, int day)" << endl;}
private:int _year;int _month;int _day;
};
int main()
{//内置类型比如intint x1 = 1;int x2={ 2 };//数组int array1[]{ 1, 2, 3, 4, 5 };int array2[5]{ 0 };//自定义类型 Point p{ 1, 2 };Date d1(2022,11,14);//用构造函数初始化Date d2{2022,11,14};//列表初始化// C++11中列表初始化也可以适用于new表达式中int* pa = new int[4]{ 0 };return 0;
}
1.2 std::initializer_list
C++11中对{1,3,4}这样的列表定义了一个新的类型 -- initializer_list
auto il = { 10, 20, 30 };
cout << typeid(il).name() << endl;
并在库中的容器的里支持了用initializer_list支持的构造函数。vector、list、map等都可以用它进行初始化。
vector v = { 1,2,3,4 };
list lt = { 1,2 };
map dict = { {"sort", "排序"}, {"insert", "插入"} };
自定义类型可以支持多个对象初始化,只需要增加initializer_list类型的构造函数即可。
2 声明
2.1 auto
自动推断类型。
auto不能推导函数参数的类型,因为在函数编译阶段,还没有传递参数,就无法推演出形参的实际类型。
C+11中已经去除了auto声明自动类型变量的功能,只可以用来进行变量类型推导。
2.2 decltype
关键字decltype将变量的类型声明为表达式指定的类型。
int main()
{const int x = 1;double y = 2.2;decltype(x * y) ret; // ret的类型是doubledecltype(&x) p; // p的类型是int*cout << typeid(ret).name() << endl;cout << typeid(p).name() << endl;return 0;
}
2.3 nullptr
3 新增容器
array --->静态数组
forward_list --->单链表
unordered_map --->哈希表
unordered_set --->哈希表
4 右值引用和移动语义
4.1 左值和右值
左值:可以取它的地址的就是左值。(左值除了被const修饰的 其余都可以修改)
右值:不能出现在赋值运算符左边的,不能被取地址的。
例如:字面常量、表达式返回值、函数返回值等。
10 x+y func(x,y)
4.2 右值引用
int main()
{10;x + y;Func(x, y);int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = Func(x, y);
}
tip:右值不能被获取地址,但是一旦被引用之后,就可以通过对引用的取地址/修改来影响右值。但这不是重点。
无论左值引用还是右值引用,都是给对象取别名。
4.3 左值引用和右值引用的比较
左值引用只能引用左值,不能引用右值。但左值引用加了const后就可以引用右值了。
const int& ra3 = 10;
右值引用只能引用右值,不能引用左值。但是可以引用move后的左值。
int&& r3 = std::move(a);
4.4右值引用的使用场景
之所以使用左值引用,目的是:
1、减少函数参数调用以及做返回值时的拷贝构造,以提高效率。
2、做输出型参数,修改返回对象。
短板:但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回, 只能传值返回。
在我们以前的实现中,当我的返回值类型非常复杂时,比如vector<vector<int>> 或者是 红黑树、哈希表时,消耗仍然大。既然我们这个临时变量马上就要析构,C++11对于此方面进行了右值引用的优化方案。
5.移动构造
拿一个string类进行说明。主要关注对象是移动构造、和移动拷贝。
// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 拷贝构造(深拷贝)" << endl;string tmp(s._str);swap(s);}// 移动构造string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 资源转移" << endl;swap(s);}
拷贝构造传入的参数是引用类型,以后还需要继续使用。所以不能直接交换,需要创建一个对象,用这个对象进行交换。
既然局部对象拷贝后,本来就需要销毁。那还为什么要创建一个新的临时变量以完成交换呢?我们直接使用这个局部对象进行交换不就好了吗?
如果实现了移动构造,在局部对象即将出作用域的时候,就会被识别称为将亡值,从而调用移动构造,减少了一次创建对象并拷贝的过程。
namespace chy
{class string{public:// 拷贝赋值string& operator=(const string& s){cout << "string& operator=(string s) -- 拷贝赋值(深拷贝)" << endl;string tmp(s);swap(tmp);return *this;}// 移动赋值string& operator=(string&& s){cout << "string& operator=(string s) -- 移动赋值(资源移动)" << endl;swap(s);return *this;}void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}string to_string(int value){bool flag = true;if (value < 0){flag = false;value = 0 - value;}string str;while (value > 0){int x = value % 10;value /= 10;str += ('0' + x);}if (flag == false){str += '-';}std::reverse(str.begin(), str.end());return str;}private:char* _str;size_t _size;size_t _capacity;};
}
移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。
当我们调用to_string()函数时,编译器会将其的返回值识别成右值,从而调用类型最匹配的移动拷贝。如果没实现移动构造和移动赋值,那依然走的是深拷贝。
int main()
{chy::string ret; ret=to_string(-3456); //移动赋值chy::string ret2=chy::to_string(-1234);//移动拷贝 return 0;
}
一些例子
int main()
{chy::string str1("hello");//拷贝构造chy::string str2(str1); // 拷贝构造chy::string str3(move(str1)); // 移动构造std::string s1("hello world");//拷贝构造std::string s2(s1); // 拷贝构造// std::string s3(s1+s2);std::string s3 = s1 + s2; // 移动构造std::string s4 = move(s1);//移动构造return 0;
}
C++11的更新内容--auto--右值引用和移动构造--1114相关推荐
- 看完这个你还不理解右值引用和移动构造 你就可以来咬我(下)
共分三篇,这是第3篇.另外两篇,看完这个你还不理解右值引用和移动构造 你就可以来咬我(上),看完这个你还不理解右值引用和移动构造 你就可以来咬我(中). 下面是新标准下的其他特性(共十点),了解一下, ...
- 看完这个你还不理解右值引用和移动构造 你就可以来咬我(中)
共分三篇,这是第2篇.另外两篇,看完这个你还不理解右值引用和移动构造 你就可以来咬我(上),看完这个你还不理解右值引用和移动构造 你就可以来咬我(下). 看完上篇,应该对右值引用和移动构造有了总体上的 ...
- 看完这个你还不理解右值引用和移动构造 你就可以来咬我(上)
共分三篇,这是第一篇.另外两篇,看完这个你还不理解右值引用和移动构造 你就可以来咬我(中),看完这个你还不理解右值引用和移动构造 你就可以来咬我(下). C++ 右值引用 & 新特性 C++ ...
- C++11:右值引用、移动构造、std::move, 以及使用emplace_back代替push_back
最近在写一段代码的时候,突然很好奇C++11中对push_back有没有什么改进以增加效率,上网搜了一些资料,发现果然新增了emplace_back方法,比push_back的效率要高很多. 1.右值 ...
- 【C++11】右值引用与移动构造、万能引用与完美转发
目录 一.右值引用 1.1 左值引用和右值引用 1.2 左值引用与右值引用比较 1.3 右值引用的使用场景和意义 二.移动构造 2.1 移动构造的实现 2.2 移动赋值 2.3 默认成员函数 2.4 ...
- C++语法——右值引用、移动构造和赋值、万能引用和转发、move和forward底层实现
目录 一.右值引用 (一).何为右值 (二).右值引用 (三).右值和左值的互相传递 ①左值->右值引用 ②右值->左值引用 (四).右值引用的自身属性 二.移动构造和移动赋值 (一).移 ...
- C++11中的右值引用(对比左值引用和常引用)、移动构造函数和引用标识符
Hello!各位同学们大家好!逗比老师最近说起来还是挺尴尬的,为什么这么说呢?因为以前我对自己的C++水平还是相当自信的,经常以"精通"来自我评价.但是最近发现自己好像对C++11 ...
- C++11中的右值引用
http://www.cnblogs.com/yanqi0124/p/4723698.html 在C++98中有左值和右值的概念,不过这两个概念对于很多程序员并不关心,因为不知道这两个概念照样可以写出 ...
- C++11中的右值引用及move语义编程
C++0x中加入了右值引用,和move函数.右值引用出现之前我们只能用const引用来关联临时对象(右值)(造孽的VS可以用非const引用关联临时对象,请忽略VS),所以我们不能修临时对象的内容,右 ...
最新文章
- linux两种方式改变文件权限,Linux更改文件权限的两种方式
- mappingResources、mappingLocations、mappingDirectoryLocations、mappingJarLocations配置映射文件时的区别
- leetcode 236. Lowest Common Ancestor of a Binary Tree | 236. 二叉树的最近公共祖先(Java)
- 7个GIF动图帮你瞬间理解三角函数
- (五)DOM4j进行XML文件的解析及生成
- 手机技巧:手机关掉这个开关,一下能省2G内存,再也不怕卡顿死机
- 从2元钱到年赚20亿元的传奇经历!相信对你一定会有很大的启发!
- 高斯滤波程序编写 opencv C++ CSU
- android计算器(按钮版)
- Linux的vi命令使用详解
- java中常见的NullPointerException异常
- VUE移动端案例整合
- python中字典的定义和操作
- Unity开发 Photon Pun 多人游戏组件
- 转帖 -- 仙4语录
- 24岁华为Java程序员工资表曝光,牛逼的人注定会牛逼
- U3D-实时PVP小地图实现
- win10此计算机未连接到网络,win10提示无法连接到此网络是怎么回事 怎么办
- 多读书,不如读好书:程序员必读的30本书
- 有哪些道理是你毕业多年后才明白的?
热门文章
- PIM-SM--理论详解
- “基尔霍夫电流定律”电子教案
- 数据挖掘的分析软件和展示工具
- onCreate与onStart区别,onStart与onResume区别
- 关于onCreate(Bundle savedInstanceState, PersistableBundle persistentState)
- Mysql 存储过程 / 存储函数
- SeekBarVolumizer.java
- C 语言到底能做什么?What can C do?
- ffmpeg图片格式转换
- 二进制部署Prometheus及监控服务