[GeekBand] C++11~14
一、关键字decltype
由对象得到对象的数据类型,例如
- Complex a(1, 2);
- decltype(a) b(3, 4);
declare type是让编译器去找到它的类型。
Decltype甚至允许你使用在函数被调用时才确定的数据类型,例如:
- template < class T1, class T2 > decltype(x + y) add(T1 x.T2 y);
则等价于新引入的->语法(与lambda表达式的语法相似)
- template < class T1, class T2 > auto add(T1 x, T2 y) - > decltype(x + y);
二、哈希容器
在C++11之前,存在hash_set,hash_multiset,hash_map,hash_multimap这几种基于哈希表的快速查找的容器;在C++11之后,hash统一更改为unordered.
unordered_set的接口为:
template < typename T, typename Hash = hash < T > , typename EqPred = equal_to < T > , typename Allocator = allocator < T >> class unordered_set;
比普通版本的容器多了这两类操作:
第一类是总的hash表大小相关的函数:
bucket_count(),max_bucket_count(),bucket_size(),bucket(const key_type& k)[返回k的bucket的下标];
第二类是和占空比相关的函数:
load_factor(),max_load_factor()/max_load_factor ( float z )[无参为取得最大占空比,有参未设置最大占空比],rehash ( size_type n )[改变大小为n并重新哈希],reserve ( size_type n )[改变大小为最适合装n个元素的哈希表并重新哈希];
(一)用法
三、lambda表达式
C++11 的 lambda 表达式规范如下:
[ capture ] ( params ) mutable exception attribute -> ret { body }
(1)
[ capture ] ( params ) -> ret { body }
(2)
[ capture ] ( params ) { body }
(3)
[ capture ] { body }
(4)
其中
- (1) 是完整的 lambda 表达式形式,
- (2) const 类型的 lambda 表达式,该类型的表达式不能更改捕获("capture")列表中的值。
- (3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
- 如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
- 如果没有 return 语句,则类似 void f(...) 函数。
- 此种形式最为常用。
- 省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)。
attribute 用来声明属性。
另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表(也就是不需传参数直接就能看到的量),具体解释如下:
- [a,&b] a变量以值的方式捕获,b以引用的方式被捕获。
- [this] 以值的方式捕获 this 指针。
- [&] 以引用的方式捕获所有的外部自动变量。
- [=] 以值的方式捕获所有的外部自动变量。
- [] 不捕获外部的任何变量。
此外,params 指定 lambda 表达式的参数。
四、右值引用与搬移语义
目的:减少不必要的Copy。很多Copy是在我们不注意的情况下产生的,比如生成一个临时对象并放到容器去的时候,就涉及了一个拷贝,例如c.insert(string("123"))。
- 左值指的是"可以"出现在=左边的东西;右值指的是"只能"出现=在右边的东西。
通常来讲,没有名称的东西都是右值,最常用的是临时对象(包括中间运算结果)。但是在C++11中,我们可以写出这样的代码
- string s1, s2;
- string() = "World";
- s1 + s2 = s2;
这其实是很奇怪的,右值竟然出现在左边并通过了编译。
所谓的右值引用,是指让左边可以"窃取"到右边的资源,而不需要先拷贝右边,再将右边析构。
以vector::insert()为例,现在它有了insert(…… &x)和insert(…… &&x)两种定义。当我们如果使用了vector<myClass>.insert(myClass(1,2))时,就会调用到insert(…… &&x)的这个版本,这个版本内部会调用一个右值引用版本的拷贝构造函数,其接口为:
myClass(myClass&& rvalue) noexcept;//这里必须有无异常声明。
其行为仅仅是一个浅拷贝,这就要求原来的rvalue不能继续被使用,否则就会发生两个对象共享一个实例的情况。
对于临时对象来说,这一点一定得以保证;
如果对于其他对象,我们如果可以通过移动语义:
- myClass a; //生成对象a
- myClass(std::move(a)) b; //利用移动语义的拷贝构造函数,是一个浅复制,执行完之后a不再可用。
move的语义可以理解为,强行将一个左值变成右值;右值的特点是,会调用右值引用版本的拷贝构造和赋值函数。这两种函数应该通过浅复制实现来减少不必要的copy,也就是说:
如果b=move(a),则会变为b<->a,发生交换(采用交换而不是只管b的原因是必须让a不再为a,不然会出现共享实例);
对于myClass(std::move(a)),则是变为"临时对象"<->a,则a充当了临时对象的角色,而a的内容直接变成了目前的这个临时对象的内容(也就是空的东西)(这是一个浅复制)。
那么现在一个关键的问题就是,这种浅拷贝版本的构造函数myClass(myClass&& rvalue) noexcept的实现到底怎么写?
首先我们必须要理解,作为myClass&& rvalue形式接受进来的参数是什么的问题。对于myClass这一函数内部,rvalue其实是一个左值,myClass&&只代表接受参数的方式,在传参之后,rvalue就是一个普通有名变量,也就是通常意义上的左值【这一点,对于普通的引用传参也是一样的。可以类比,对于子函数,如果以引用形式接受参数,在子函数域内新的实参就是普通变量,和我采用了引用传递还是值传递没有什么关系】
在移动语义版本中,我们不再需要为指针变量分配新的空间,只需要:1.利用原对象对非指针变量进行初始化;2.简单改变指针指向;3.使原指针变为空指针。这一步是必须的,否则由于内存回收时调用析构函数会把原地址空间释放掉。并且,在析构的时候必须检查是否是空指针在进行delete,否则会发生内存泄露。
五、 容器
一、 Array容器类型
就是C++的数组的一个新包装。他的引入可以说就是为了使用数组时也可以使用容器的那些操作,是比较简单的一个容器。
二、 emplace操作
在C++11版本以后各个容器都引入了emplace的操作。
Emplace的意思是,构造的同时进行插入:
- std::vector < Foo > v;
- v.emplace(someIterator, 42, 3.1416); // 没有临时变量产生
- v.insert(someIterator, Foo(42, 3.1416)); // 需要产生一个临时变量
- v.insert(someIterator, {
- 42, 3.1416
- }); // 需要产生一个临时变量
[GeekBand] C++11~14的更多相关文章
- JavaSE_ API常用对象 总目录(11~14)
JavaSE学习总结第11天_开发工具 & API常用对象111.01 常见开发工具介绍11.02 Eclipse和MyEclipse的概述11.03 Eclipse的下载安装及卸载11.04 ...
- Intel Artificial Intelligence Conference(2018.11.14)
时间:2018.11.14地点:北京国贸大酒店
- 第26次Scrum会议(11/14)【欢迎来怼】
一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,阚博文 小组照片 二.开会信息 时间:2017/11/14 11:35~11:57,总计22min.地点:东北 ...
- Notes of Daily Scrum Meeting(11.14)
Notes of Daily Scrum Meeting(11.14) 今天是项目第三周的周五,按原计划这时我们的项目应该已经要进入尾声进行组装调试了,但由于之前放假还有队员们的 效率比较低的原因,我 ...
- C++11/14笔记
目录 语言层面 模板表达式中的空格 nullptr和std::nullptr_t 自动推导类型----auto 一致性初始化----Uniform Initialization 初始化列表(initi ...
- 基数排序的可复用实现(C++11/14/17/20)
基数排序,是对整数类型的一种排序方法,有MSD (most significant digit)和LSD (least significant digit)两种.MSD将每个数按照高位分为若干个桶(按 ...
- JZOJ 11.14 提高B组反思
JZOJ 11.14 提高B组反思 T1 题目虽然有点高大上,但是很容易懂 有一个\(d\)维空间,同时有一个长度为\(2n\)的操作序列,每个操作往某一维的正方向或反方向走一格,问多少种方案使得最后 ...
- 2021.11.14 CF1583E Moment of Bloom(LCA+图上构造)
2021.11.14 CF1583E Moment of Bloom(LCA+图上构造) https://www.luogu.com.cn/problem/CF1583E 题意: She does h ...
- [GeekBand] 探讨C++新标准之新语法——C++ 11~14
一. 可变参数模板(Variadic Templates) 在C++11中,出现了参数数目可变的模板,这部分在之前C++高级编程的时候就有学习到. 其实,在C中就有类似的设定.最常用的printf() ...
随机推荐
- Jquery中$与$.fn的差别
当今web开发往往离不开Jquery的使用,Jquery以其简洁的使用方式.良好的浏览器兼容性赢得了软件研发同行的青睐,作为当中的一员,自然也不例外,虽然刚開始时非常排斥Jquery,今天我谈一下对J ...
- ubuntu下tomcat启动巨慢分析
在一个ubuntu14新环境部署tomcat,通过CI启动一个应用时,启动耗时达到15分钟之久.仔细看tomcat输出的耗时统计日志发现如下日志: Creation of SecureRandom i ...
- 我和ip_conntrack不得不说的一些事
面对让人无语的ip_conntrack,我有一种说不出的感觉!自从接触它到现在,已经两年多了,其间我受到过它的恩惠,也被它蹂躏过,被它玩过,但是又不忍心舍弃它,因为我找不到更好的替代.工作中,学习中, ...
- 小白日记39:kali渗透测试之Web渗透-SQL手工注入(一)-检测方法
SQL手工注入(一) SQL注入:通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.[SQL注入原理] ##服务端程序将用户输入参数作为查询 ...
- 关于struts2的modelDriven
今天做毕业设计,前台往后台赋值,习惯性的用了modelDriven.但是刚写完就奇怪它的机理是怎样的,它怎么知道我前台传的参是哪个Model的属性(之前用servlet都是手动),于是手贱的ctrl点 ...
- Android(java)学习笔记94:关于广播接收者的注册和使用心得
下面我们先看一部分代码,由代码进行进一步的深入: registerReceiver( new BroadcastReceiver() {//onReceive中代码的执行时间不要超过5s,androi ...
- ASP.NET MVC and jqGrid 学习笔记 5-添加数据
据介绍,jqgrid有3种编辑数据的方式: Cell Editing 只允许修改某一个单元格内容 Inline Editing 允许在jqGrid中直接修改某一行的数据 Form Editing 弹出 ...
- lk启动流程详细分析
转载请注明来源:cuixiaolei的技术博客 这篇文章是lk启动流程分析(以高通为例),将会详细介绍下面的内容: 1).正常开机引导流程 2).recovery引导流程 3).fastboot引导流 ...
- 在IIS7.5上添加.NET4.0程序的虚拟目录时提示ASP.NET 4.0尚未在 Web 服务器上注册
使用VS2010创建web应用程序时出现如下提示: ASP.NET 4.0尚未在 Web 服务器上注册. 解决方法: 首先IIS应用程序池添加 net framework4.0版本. 接着找到C:\W ...
- 一个把List<String>转化为以","隔开的字符串的方法
import java.util.ArrayList; import java.util.List; /** * 集合操作 * @author intrl * @date 2010-12-15 * @ ...