你不知道的c++11
随着C++11的发布,C++这门语言有了本质上的提升。C++14,C++17的相继推出,更是让C++这门语言达到了一个新高度。新的标准库设施,新的语法,让我们得以书写更加安全、便捷、高效的程序。
2018年6月编程语言排行榜:
那么这些新的语法究竟是什么?它们如何使用?能为我们编程带来哪些便利?这便是本文所探讨的。
本文参考部分资料,文末已给出原文章地址。
新的空指针类型——nullptr
适用度:★★★★★
nullptr是一种特殊的字面值,它可以转化为任意一种指针类型。 原来我们初始化一个空指针都是直接将他赋值为NULL,但NULL实际上是一个宏,其值相当于0。
编译器是这么定义NULL的:
#ifdef __cplusplus //如果定义__cplusplus宏,说明正在编译C++语言
#define NUll 0
#else
#define NULL ((void *)0)
#endif
也许你会想“我们用NULL还不是照样吊打集训队”,nullptr好像并没有什么用。
考虑这样一段代码:
int f(int x){
//do something
}
int f(int *x){
//do something
}
int main(){
f(NULL);
}
很显然,编译失败,对f的调用有二义性。因为NULL相当于0,既可转化为指针,也可转化为整形。将NULL换做nullptr即可,nullptr便是为了解决这种二义性的问题而诞生的。
条件允许的前提下,尽量使用nullptr,它比NULL更加安全, 原来这样写:
int a = NULL;
int *b = NULL;
现在应该这样写:
int a = NULL;
int *b = nullptr;
避免奇葩错误——constexpr变量
适用度:★★★★☆
在编程中,我们经常遇到需要定义常量的情况,但有些常量却并不是你所想的“常量”。因而会引发一些意想不到的错误。
例如:
int a;
const int b = a + 10;
int c[b];//错误,b不是一个常量表达式,它的值每次运行都有可能不一样。
b的确是**一个常量——它的值在程序的执行期间不会被修改**,但是**它并不是常量表达式——每次执行程序时都为同一个值,且程序执行期间无法被修改。**
使用**constexpr**而非const来声明常量,让编译器来帮你检查常量是不是每次程序执行都为同一个值。
int a;
constexpr b = a + 10;//错误!a不是常量表达式!
int a;
const int b = a + 10;
constexpr int c = b + 10;//错误,b为常量,但不是常量表达式!
const int a = 10;
const int b = a + 10;
constexpr int c = b + 10;//正确
省事好帮手——auto类型指示符
适用度:★★★★★
有些类型名字太长,难以拼写,浪费时间。怎么办?
知道函数的作用,却无法拼写其返回类型,无法保存其返回值。怎么办?
这个时候auto类型指示符就能够助我们一臂之力了。
原来我们这么写:
vector<int> vec;
for(vector<int>::iterator it = vec.begin();it != vec.end();it++)//Do something
现在可以简单的这么写:
vector<int> vec;
for(auto it = vec.begin();it != vec.end();it++)//Do something
怎么样?程序瞬间清爽了许多有木有。而且还可以节约大量宝贵的时间
因为编译器是依靠初始值来推断auto变量的类型的,所以auto变量必须要有初始值。
即使是这样也不行:
auto a;
a = 10;
当然,也不能用auto来定义数组
auto和引用一起会产生一些奇怪的问题:
int i = 1,&r = i;//定义变量i,r为i的引用
auto p = r;//没错,p的值为int,其值为1
为什么?因为引用即别名。正如我们熟知的,使用引用其实是使用引用的对象,特别当引用被用作初始值的时候,真正参与初始化的其实是引用对象的值。此时编译器以引用对象的类型作为auto的类型。
自动类型推断——decltype类型指示符
适用度:★★★★☆
上文提到了auto的用法,有时候我们想要用表达式的类型初始化一个变量,却并不想用表达式的值初始化这个变量。这个时候decltype类型指示符就可以派上用场了。
剧透:下文位置返回类型配合decltype类型指示符有惊喜
我们可以这样用decltype类型指示符来定义变量:
int a = 10;
decltype(a) b;
b = 20;
但是要注意,decltype只会用表达式的返回值进行推断,并不会执行表达式。例如:
int f(){
cout << "Hello decltype!" << endl;
return 0;
}
decltype(f()) i = 123;//i的值为123
//程序运行并不会有任何输出,因为f函数并没有实际执行。
int i = 1;
decltype(i = 123) b = i;
cout << i << endl;//输出1,因为i = 42表达式并未实际执行
decltype和auto都可以完成类型推断的任务,那么它们有什么不同呢?
1.处理引用
int i = 1,&r = i;//定义int型变量i,r为i的引用。
auto a = r;//此时a的类型为int
decltype(r) b = r;//此时b的类型为int&,即为int的引用。
2.处理顶层const
这里引入一个概念:
1.底层const,对象所指向的对象是const的。 2.顶层const,对象本身是const的。
auto会忽略掉顶层const和引用,但是会保留底层const。
const int ci = i,&cr = ci;
auto a = ci;//a为int,顶层const被忽略
auto b = cr;//b为int,顶层const和引用均被忽略
auto c = &ci;//c为指向常量int的指针,保留底层const
如果要使auto类型为顶层const:
int i = 1;
const auto a = i;//a为const int 类型
如果decltype使用的表达式是一个变量,decltype会返回该变量的类型(包括引用和顶层const)。
循环宏的优秀替代品——范围for语句
适用度:★★★★★
什么?就算有了auto类型指示符,遍历容器/数组每一个元素你还是嫌麻烦?没事,让范围for语句来帮你。
原来这么遍历容器/数组每一个元素
vector<int> vec;
for(auto it = vec.begin();it != vec.end();it++)
cout << *it << " ";
现在这么写:
vector<int> vec;
for(auto it : vec)
cout << it << " ";
注意,范围for语句只能遍历每一个元素,所以像遍历1到10这种操作还是得自己乖乖写for循环:)。
复杂返回值必备——尾置返回类型
适用度:★★★★☆
普通函数完全不必要尾置返回类型,但是当函数返回类型复杂起来时,尾置返回类型就很有用了。
int (*func(int i))[10]{
//Do something
}
//func(int i)表示调用函数时,需要一个int类型的参数;
//(*func(int i))表示对调用func的结果执行解引用的操作;
//(*func(int i))[10]表示解引用之后得到一个维度为10的数组;
//int (*func(int i))[10]表示数组的数据类型为int;
很复杂,对吧?(当然对于dalao来说小菜一碟)当返回类型更加复杂时,常规写法将会成为Debug噩梦。(话说Markdown好像识别不了尾置返回类型诶)。
//返回一维数组
auto func(int i) -> int(*)[10]{
//Do something
}
还有更复杂的(我太蒻了给不出常规写法了)
二维数组:
auto func(int i) -> int(*)[10][10]{
//Do something
}
二重指针:
auto func(int i) -> int **{
//Do something
}
除了数组特殊一些以外,平时定义变量怎么写,尾置返回类型就怎么写。程序瞬间清爽了许多有木有。
如果返回值更加复杂,连尾置返回类型的作用都显得微乎其微了怎么办?这时候——
配合decltype食用效果更佳
auto func(int a,int b) -> decltype(a+b){
//Do something
return a+b;//函数的返回类型即为int
}
什么?你连尾置返回类型都嫌麻烦?C++14可以满足你的需求。没错,连尾置返回类型都可以省了,直接返回类型auto就可以了Orz。
你不知道的c++11的更多相关文章
- 地区sql
/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...
- 翻译连载 | 第 11 章:融会贯通 -《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 你不知道的JavaScript 上卷 2/11
第一部分——作用域和闭包 第一章 作用域是什么 1.几乎所有编程语言最基本的功能之一,就是能够储存变量当中的值,并且能在之后对这个值进行访问或修改.事实上,正是这种储存和访问变量的值的能力将状态带给了 ...
- MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句
第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...
- 开源 VS 商业,消息中间件你不知道的那些事
11月23日,新炬网络中间件技术专家刘拓老师在DBA+社群中间件用户组进行了一次主题为“开源 VS 商业,消息中间件你不知道的那些事”的线上分享.小编特别整理出其中精华内容,供大家学习交流. 嘉宾简介 ...
- 另5个你不知道的HTML5接口API
原文地址: 5 More HTML5 APIs You Didn’t Know Existed 演示地址: 全屏API Demo 原文日期: 2012年11月08日 翻译日期: 2013年08月13日 ...
- 你不知道的 页面编码,浏览器选择编码,get,post各种乱码由来
原文:你不知道的 页面编码,浏览器选择编码,get,post各种乱码由来 asp.net页面编码和浏览器的选择编码 每个asp.net的朋友都知道,在新版本的visual studio,在没有任何设置 ...
- 【读书笔记】-- 你不知道的JavaScript
<你不知道的JavaScript>是一个不错的JavaScript系列书,书名可能有些标题党的意思,但实符其名,很多地方会让你有耳目一新的感觉. 1.typeof null === &qu ...
- [javascript 实践篇]——那些你不知道的“奇淫巧技”
1. 空(null, undefined)验证 刚开始,我是比较蠢的验证(我还真是这样子验证的) if (variable1 !== null || variable1 !== undefined | ...
随机推荐
- POJ1040 Transportation
题目来源:http://poj.org/problem?id=1040 题目大意: 某运输公司要做一个测试.从A城市到B城市的一条运输线路中有若干个站,将所有站包括A和B在内按顺序编号为0到m.该路线 ...
- day01笔记
linux基本命令的学习: 1.查看主机名 hostname 2.修改主机名 hostnamectl set-hostname s16ds 3.linux命令提示符 [root@s16ds ~]# # ...
- 原生JS轮播-各种效果的极简实现(二)面向对象版本的实现和优化
之前写了一篇原生JS轮播,不过是非面向对象的,并且也没有添加上自动轮播.这里来写一下如何优化和进阶. 这里简单地介绍一下之前的代码,这是html结构 <body> <div clas ...
- mongoose的安装与使用(书签记录) 2017
Windows7环境下安装:慕课网中的手记 http://www.imooc.com/article/12447 关于在CMD中对Mongo API的调用,从这些API调用中我们也可以更容易地理解在n ...
- Ubuntu16.04双网卡绑定
服务器经常有多个网卡,为了保证网络冗余性,一个网卡出现故障时,不导致网络服务中断,可以懂多网卡网卡绑定来解决此问题. 环境: 系统:Ubuntu16.04 网卡:em1 em2 ip:192.168. ...
- jquery——解决鼠标移入移出导致盒子不停移动的bug
使用mouseover().mouseout()时会出现这样一种情况,鼠标快速多次移入移出后这个盒子会在鼠标不动后继续运动 代码如下: <!DOCTYPE html> <html l ...
- SpringBoot源码篇:深度分析SpringBoot如何省去web.xml
一.前言 从本博文开始,正式开启Spring及SpringBoot源码分析之旅.这可能是一个漫长的过程,因为本人之前阅读源码都是很片面的,对Spring源码没有一个系统的认识.从本文开始我会持续更新, ...
- javascript模块化编程规范
一.javascript模块化编程规范: 二.关于commenjs规范和AMD规范: 根本不同:前者用于服务器端同步加载模块:后者是客户端异步加载模块. 同点:两者都有一个全局函数require(), ...
- webpack.config.js====CSS相关:插件optimize-css-assets-webpack-plugin
1. 安装:主要是用来压缩css文件 cnpm install --save-dev optimize-css-assets-webpack-plugin cssnano 2. webpack.con ...
- java 基础 03 运算符 分支结构 循环结构
今天内容: (1)运算符 (2)分支结构 (3)循环结构 1运算符 1.1赋值运算符 (1)简单赋值 = 表示赋值运算符,用于将=右边的数据赋值给=左边的变量来覆盖原来的数值. 笔试题: ia == ...