nullptr
:空指针
C++11
引入,规定空指针的值,替换C++98
中的NULL
关键字。
在C++98
中,编译器有这样的语句:#define NULL 0
,这使得NULL
的类型与int
相同,造成了重载函数时可能的混淆问题。如下:
1 | void func(int a); |
为解决此问题,C++11
引入了nullptr
关键字为空指针赋值,其类型为nullptr_t
,与int
类型不同。
值得一提的是,编译器定义nullptr_t
的方法很有意思。因为此类型以_t
结尾,说明非原生关键字,而是由编译器定义出来。
1 |
|
由上可见,编译器定义nullptr_t
为nullptr
的类型,甚是巧妙。
constexpr
:常量表达式
C++11
引入,与const
关键字使用方法类似,用以修饰一个变量或函数的值为常量表达式,即为编译期常量。
在C++
标准中,关于数组长度有这样的规定:
The elements field within square brackets [], representing the number of elements in the array, must be a constant expression, since arrays are blocks of static memory whose size must be determined at compile time, before the program runs.
中括号中的数组长度必须为常量表达式,因为数组代表着一组在编译时就被确定的静态存储区域,在程序运行前就已经被定死。
From: Arrays - C++ Tutorials
在平常代码中,我们经常将const int
的值作为数组长度,但实际上这是违反C++
标准的,因为const int
只要求其初始化后不得再被改变,而不要求其在编译期就计算出结果。换而言之,它并不是合法的常量表达式。我们平常的用法只是编译器提供的合理化扩展。一个反例如下。
1 | int a; |
以上代码中的b
是const int
类型,但是却在运行时才被初始化,其值也无法在编译期计算出来。为此,我们才引入了constexpr
关键字,其标志着编译时绝对能够准确计算的值和函数。
constexpr
修饰变量
在定义一般变量时,只需要写上constexpr
关键字即可定义一个编译期常量。constexpr
可以与 const
连用。在为constexpr
变量赋值时,赋值号右侧的语句必须也是常量表达式。
1 | constexpr int a; |
constexpr
修饰函数返回值
用constexpr
修饰的函数就变成了“两用函数”:
- 在传入参数均为
constexpr
类型时其返回值也为constexpr
类型。 - 在传入参数不均为
constexpr
类型时其返回值不为constexpr
类型,其表现与正常函数相同。
1 | constexpr int fib(const int n) |
在C++14
之前,constexpr
变量无法参与if
,
switch
,
while
语句运算。以下代码在C++14
及之后的版本才合法:
1 | constexpr int fib(const int n) |
if - switch
:初始化语句
C++11
引入,在if
,
switch
语句括号内可以插入初始化语句。定义出来的变量与if
,
switch
生命周期相同。
1 | if (int a = 1; a != 5) |
[[fallthrough]]
,
[[likely]]
和[[unlikely]]
C++20
引入,用以给编译器打标记。
[[fallthrough]]
标记用于不添加break
语句的case
语段末尾,可以消除警告。
[[likely]]
和[[unlikely]]
可以用于while
,
if
,
else if
和case
等表达式后面,为CPU分支预测提供参考,可以优化程序运行速度。
1 | enum class MID { ZOE, YASUO, AHRI, LUCIAN, VN }; |
range-based for
:基于范围的for
循环语句
C++11
引入,给予for
循环新写法。
1 | int arr[]{1, 2, 3, 4, 5}; |
自C++20
起,range-based for
支持初始化语句。
1
2
3
4for(auto arr = getArr(); auto a : arr)
{
...
}
structured binding
:结构化绑定
C++17
引入,可以实现一行内拆包的操作。
1 | std::pair<int, char> p{1, 'a'}; |
对于自己定义的结构体也可以直接拆包,但是无法完全拆包继承类或者类的private
项。
1 | struct top |
与元组结合实现函数的多返回值
std::tuple
在C++11
中引入。我们可以利用结构化绑定和std::tuple
快速实现函数的多返回值。使用std::tuple
需要包含<tuple>
头文件。
1 | // 指定函数返回含有一个float,一个char和一个int的元组类型 |