[C++11] 新特性总结
C++11新增加了哪些新特性?一般而言,大概有以下四个方面:
- “语法糖”:
nullptr
,auto
自动类型推导,范围for循环,初始化列表, lambda表达式等 - 右值引用和移动语义
- 智能指针
- C++11多线程编程:
thread
库及其相配套的同步原语mutex
,lock_guard
,condition_variable
, 以及异步std::furture
1. “语法糖”
c++11新增加了一些语法糖,其中常用的就是auto和lambda。
1.1 auto自动类型推导
C语言也有auto关键字,但是其含义只是与static变量做一个区分,一个变量不指定的话默认就是auto。。因为很少有人去用这个东西,所以在C++11中就把原有的auto功能给废弃掉了,而变成了现在的自动类型推导关键字。用法很简单不多赘述,
比如写一个auto a = 3, 编译器就会自动推导a的类型为int. 在遍历某些STL容器的时候,不用去声明那些迭代器的类型,也不用去使用typedef就能很简洁的实现遍历了。
auto的使用有以下两点必须注意:
- auto声明的变量必须要初始化,否则编译器不能判断变量的类型。
- auto不能被声明为返回值,auto不能作为形参,auto不能被修饰为模板参数
关于效率: auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响。另外,auto并不会影响编译速度,因为编译时本来也要右侧推导然后判断与左侧是否匹配。
关于具体的推导规则,可以参考这里
1.2 lambda表达式
lambda表达式是匿名函数,可以认为是一个可执行体functor,语法规则如下:
[捕获区](参数区){代码区};
如
auto add = [](int a, int b) {return a + b};
就我的理解而言,捕获的意思即为将一些变量展开使得为lambda内部可见,具体方式有如下几种
- [a,&b] 其中 a 以复制捕获而 b 以引用捕获。
- [this] 以引用捕获当前对象(
*this
) - [&] 以引用捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
- [=] 以复制捕获所有用于 lambda 体内的自动变量,并以引用捕获当前对象,若存在
- [] 不捕获,大部分情况下不捕获就可以了
一般使用场景:sort等自定义比较函数、用thread起简单的线程。
2. 右值引用与移动语义
右值引用是C++11新特性,它实现了转移语义和完美转发,主要目的有两个方面
- 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率
- 能够更简洁明确地定义泛型函数
C++中的变量要么是左值、要么是右值。通俗的左值定义指的是非临时变量,而左值指的是临时对象。左值引用的符号是一个&,右值引用是两个&&
移动语义
转移语义可以将资源(堆、系统对象等)从一个对象转移到另一个对象,这样可以减少不必要的临时对象的创建、拷贝及销毁。移动语义与拷贝语义是相对的,可以类比文件的剪切和拷贝。在现有的C++机制中,自定义的类要实现转移语义,需要定义移动构造函数,还可以定义转移赋值操作符。
以string类的移动构造函数为例
MyString(MyString&& str) {std::cout << "Move Ctor source from " << str._data << endl;_len = str._len;_data = str._data;str._len = 0;str._data = NULL;
}
和拷贝构造函数类似,有几点需要注意:
- 参数(右值)的符号必须是&&
- 参数(右值)不可以是常量,因为我们需要修改右值
- 参数(右值)的资源链接和标记必须修改,否则,右值的析构函数就会释放资源。转移到新对象的资源也就无效了。
标准库函数std::move --- 将左值变成一个右值
编译器只对右值引用才能调用移动构造函数,那么如果已知一个命名对象不再被使用,此时仍然想调用它的移动构造函数,也就是把一个左值引用当做右值引用来使用,该怎么做呢?用std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
详情请见:[C++11] 右值引用和移动语义
3.智能指针
核心思想:为防止内存泄露等问题,用一个对象来管理野指针,使得在该对象构造时获得该指针管理权,析构时自动释放(delete).基于此思想C++98提供了第一个智能指针:auto_ptr
auto_ptr
基于所有权转移的语义,即将一个就的auto_ptr赋值给另外一个新的auto_ptr时,旧的那一个就不再拥有该指针的控制权(内部指针被赋值为null),那么这就会带来一些根本性的破绽:
- 函数参数传递时,会有隐式的赋值,那么原来的auto_ptr自动失去了控制权
- 自我赋值时,会将自己内部指针赋值为null,造成bug
因为auto_ptr的各种bug,C++11标准基本废弃了这种类型的智能指针,转而带来了三种全新的智能指针:
- shared_ptr,基于引用计数的智能指针,会统计当前有多少个对象同时拥有该内部指针;当引用计数降为0时,自动释放
- weak_ptr,基于引用计数的智能指针在面对循环引用的问题将无能为力,因此C++11还引入weak_ptr与之配套使用,weak_ptr只引用,不计数
- unique_ptr: 遵循独占语义的智能指针,在任何时间点,资源智能唯一地被一个unique_ptr所占有,当其离开作用域时自动析构。资源所有权的转移只能通过
std::move()
而不能通过赋值
详情请见:[C++11] 智能指针
4、C++11多线程编程
4.1 线程
std::thread
- 创建std::thread,一般会绑定一个底层的线程。若该thread还绑定好函数对象,则即刻将该函数运行于thread的底层线程。
- 线程相关的很多默认是move语义,因为在常识中线程复制是很奇怪的行为。
- joinable():是否可以阻塞至该thread绑定的底层线程运行完毕(倘若该thread没有绑定底层线程等情况,则不可以join)
- join():本线程阻塞直至该thread的底层线程运行完毕。
- detach():该thread绑定的底层线程分离出来,任该底层线程继续运行(thread失去对该底层线程的控制)。
4.2 互斥量
为了避免多线程对共享变量的一段操作会发生冲突,引入了互斥体和锁。
std::mutex
- 互斥体,一般搭配锁使用,也可自己锁住自己(lock(),unlock())。
- 若互斥体被第二个锁请求锁住,则第二个锁所在线程被阻塞直至第一个锁解锁。
std::lock_guard
- 简单锁,构造时请求上锁,释放时解锁,性能耗费较低。适用区域的多线程互斥操作。
std::unique_lock
- 更多功能也更灵活的锁,随时可解锁或重新锁上(减少锁的粒度),性能耗费比前者高一点点。适用灵活的区域的多线程互斥操作。
4.3 原子变量
原子变量的意思就是单个最小的、不可分割的变量(例如一个int),原子操作则指单个极小的操作(例如一个自增操),C++的原子类封装了这种数据对象,使多线程对原子变量的访问不会造成竞争。(可以利用原子类可实现无锁设计)
std::atomic_flag
- 它是一个原子的布尔类型,可支持两种原子操作。(实际上mutex可用atomic_flag实现)
- test_and_set(): 如果atomic_flag对象被设置,则返回true; 如果atomic_flag对象未被设置,则设置之,返回false
- clear():清除atomic_flag对象。
std::atomic<T>
- 对int, char, bool等基本数据类型进行原子性封装(其实是特化模板)。
- store():修改被封装的值。
- load(): 读取被封装的值。
4.4 条件变量
条件变量一般是用来实现多个线程的等待队列,即主线程通知(notify)有活干了,则等待队列中的其它线程就会被唤醒,开始干活。
std::condition_variable
- wait(std::unique_lock<std::mutex>& lock, Predicate pred = [](){return true;}):pred()为true时直接返回,pred()为false时,lock必须满足已被当前线程锁定的前提。执行原子地释放锁定,阻塞当前线程,并将其添加到等待*this的线程列表中。
- notify_one()/notify_all():激活某个或者所有等待的线程,被激活的线程重新获得锁。
参考:
1、深入理解C++11:C++11新特性解析与应用
2、深入应用C++11:代码优化与工程级应用
3、Effective Modern C++
[C++11] 新特性总结相关推荐
- IntelliJ IDEA 使用 Java 11新特性以及Java 8 以来的Java 11新特性介绍
文章目录 Java 11 安装 IDEA 设置 特性1:lambda表达式中允许使用var 特性2: String新增REPEAT 方法,方便拷贝字符串 特性3: 文件读写更方便:readString ...
- Java 11 新特性
2019独角兽企业重金招聘Python工程师标准>>> Java 11 新特性 转载于:https://my.oschina.net/u/3764794/blog/2993127
- C++11新特性中的匿名函数Lambda表达式的汇编实现分析(二)
2019独角兽企业重金招聘Python工程师标准>>> C++11新特性中的匿名函数Lambda表达式的汇编实现分析(一) 首先,让我们来看看以&方式进行变量捕获,同样没有参 ...
- C++11 新特性之std::thread
C++11 新特性之std::thread 原文:https://blog.csdn.net/oyoung_2012/article/details/78958274 从C++11开始,C++标准库已 ...
- C++11新特性之新类型与初始化
C++11新特性之新类型与初始化 snoone | 2016-06-23 11:57 浏览量(148) 评论(0) 推荐(0) 数据 这是C++11新特性介绍的第一部分,比较简单易懂, ...
- Java 11新特性解读
概述 美国当地时间9月25日,Oracle 官方宣布 Java 11 (18.9 LTS) 正式发布,可在生产环境中使用!这是自 Java 8 后的首个长期支持版本,将支持到2026年,可以使用下面的 ...
- C++11新特性decltype
该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105042574 C ...
- 深入浅出之C++11新特性
1. auto类型赋予新含义 1.1 auto类型定义 在之前的 C++ 版本中,auto 关键字用来指明变量的存储类型,它和 static 关键字是相对的.auto 表示变量是自动存储的,这也是编译 ...
- 《深入理解C++11:C++ 11新特性解析与应用》——导读
前 言 为什么要写这本书 相比其他语言的频繁更新,C++语言标准已经有十多年没有真正更新过了.而上一次标准制定,正是面向对象概念开始盛行的时候.较之基于过程的编程语言,基于面向对象.泛型编程等概念的C ...
- C++11 新特性简介
1.auto auto是旧关键字,在C++11之前,auto用来声明自动变量,表明变量存储在栈,很少使用.在C++11中被赋予了新的含义和作用,用于类型推断. auto关键字主要有两种用途:一是在变量 ...
最新文章
- python导入其他py文件-Python如何import其它.py文件及其函数
- 如何在spring中读取properties配置文件里面的信息
- java 委托_面试官:java双亲委派机制及作用
- 根据数据库表gengxin实体类_ASP.NET开发实战——(十二)数据库之EF Migrations
- 这难道不是.NET5的bug? 在线求锤?
- Django 和 html
- LeetCode 2086. 从房屋收集雨水需要的最少水桶数(贪心)
- 开发Adobe AIR移动应用程序的考虑事项
- Bootstrap框架(基础篇)之列表,表格,表单
- Enumerator yielder.yield 与 Proc.yield 区别
- JavaScript动态生成表格
- 计算机诗人 原理,自动作诗器,藏头诗软件生成器原理是什么?
- 中证300、500、800成分股调整时间
- html版权登记怎么打,版权符号怎么输入_Html版权符号怎么打
- 单片机晶振电路的设计与计算
- js的数据类型,深拷贝和浅拷贝的原理,loda实现一个深拷贝
- 2018中国大学生程序设计竞赛 – 网络选拔赛 1001 Buy and Resell [模拟]
- Unity 4.6.2 iOS 64位支持
- stack在python中是什么意思_python中的栈指的是什么
- 高性能分布式游戏服务器框架
热门文章
- 【李宏毅2020 ML/DL】P75 Generative Adversarial Network | Conditional GAN
- ack过来服务器未响应,DHCP服务器问题:抓不到ACK包
- java实现 mysql导入_怎么用java实现mysql数据库的导入导出
- 中国象棋程序的设计与实现(十)--棋盘的定义和绘制
- 使用MATLAB转换图片为数据进行vga显示
- html5开发桌面程序调用dll,使用Visual Studio开发Html5应用
- User Agent跨站攻击
- oracle 01157,Oracle数据库启动时出现ORA-01157和ORA-01110问题
- Postgresql Hot_Standby 流复制 基于Linux 对postgresql 和 linux 会基本的操作
- 技术博客2013年2月份头条记录