C++11新增类型:
- 整型
long longunsigned long long
- 字符表示
char16_tchar32_t
C++11 扩大了用大括号起的列表(初始化列表)的适用范围。使其可用于所有内置类型和用户定义类型(即类对象)。列表初始化的三种方式:
- 使用初始化列表时,可添加
等号(=),也可不添加。int x = {5}; short quar[5] {4,5,6,2,1};
- 可以用于
new表达式中int *ar = new int [4] {2,4,6,7}; C++11
- 创建对象时,可使用
大括号(而不是圆括号)括起来的列表来调用构造函数。class Stump { private: int roots; double weight; public: Stump(int r,rouble w) : roots(r), weight(w) {} }; Stump s1(3,15.6); // old style Stump s2{5,43.4}; // C++11 Stump s3{4,32.1}; // C++11
-
初始化列表语法可防止缩窄,即禁止将数值赋给无法存储它的数值变量,即将值存储到比它“窄”的变量中。
-
编译器会禁止变窄类型的转换,但允许在范围内变宽的转换。
-
C++11中提供
initializer_list模板类,可用作构造函数的参数。 -
如果类有接受
initializer_list作为参数的构造函数,则初始化列表语法就只能用于该构造函数。 -
列表中的元素必须是
同一种类型或者可转换为同一种类型。
-
C++11使用auto关键字实现自动类型推断。 -
要求进行显式初始化,让编译器能够将变量的类型设置为初始值的类型。
-
auto关键字也可简化模板声明。
-
decltype关键字:将变量的类型声明为表达式指定的类型。
template <typename T, typename U> void ef(T t, U u) { decltype(T*U) tu; ... }
-
C++11新增函数声明语法:在函数名和参数列表后面指定返回类型。
double f1(double,int); // 传统方式 auto f2(double,int)->double; // C++11中的新语法
-
使用 decltype来指定模板函数的返回类型:
template<typename T, typename U> auto eff(T t, U u) -> decltype(T*U) { // 当编译器遇到 ef的参数列表时,T和 U不再作用域内,因此必须在参数列表后使用decltype。 .... }
解决标识符冗长或复杂的问题。
- 早期使用
typedef- 不能用于模板部分具体化
typedef std::vector<std::string>::iterator itType; - C++11提供
using=- 可用于模板部分具体化
template <typename T> using arr = std::array<T,int>; // 模板部分具体化
C++11 新增关键字 nullptr来表示空指针。它是指针类型,不能转换为整型类型。
为向后兼容,C++11仍允许使用 0 来表示空指针,因此表达式 nullptr==0 为 true。
因为在程序中使用 new 分配内存,未将其及时 delete释放。引入智能指针auto_ptr。
C++11抛弃auto_ptr,并新增了三种智能指针:unique_ptr、shared_ptr 和 weak_ptr。
指出函数不会引发异常有一定的价值,所以C++11添加了关键字noexpect:
void f875(short, short) noexpect; // 不会抛出异常在C++11中新增一种枚举。使用 class 或者 struc t来定义。
enum old1 {yes,no,maybe}; // 传统方式
enum class New1 {never,sometimes,often,always}; // 新方式
enum struct New2 {never,lever,sever}; // 新方式新枚举要求进行显式限定,以避免名称冲突。所以在引用枚举时,则使用
New1::never;
New2::never;-
显式转换运算符- 早期的自动类型转换会导致意外问题,所以在C++11中引入关键字
explicit,以禁止单参数构造函数导致的自动转换。
- 早期的自动类型转换会导致意外问题,所以在C++11中引入关键字
-
类内成员初始化- 可使用等号或者大括号版本的初始化,但不能使用圆括号版本的初始化。
- 类内成员初始化,可避免在构造函数中编写重复的代码。
-
基于范围的for循环
double price[5] = {4.99,10.99,6.87,7.99,8.49}; for (auto x : price) std::out << x << std::endl;
- 如果要在循环中修改数组或容器中的每个元素,可使用引用类型。
-
新的STL容器
- C++11新增STL容器:
forward_list,unordered_map,unordered_multimap,unordered_set,unordered_multiset。 - C++11新增模板array,实例化时,可指定元素类型和固定的元素数。
- C++11新增STL容器:
-
新的STL方法
- C++11新增STL方法
cbegin()cend()crbegin()crend()
- 其中
crbegin()、crend()是rbegin()、rend()的const版本。 - 除传统的
复制构造函数和常规赋值运算符外,STL容器还有移动构造函数和移动赋值运算符。
- C++11新增STL方法
-
valarray升级
- C++11中添加了两个函数 begin() 和 end()。都接受 valarray 作为参数,并返回迭代器。
-
抛弃export
- C++98新增
- C++终止用法,但为了兼容还保留关键字 export。
-
尖括号
- C++在声明嵌套模板时不再需要使用空格将尖括号分开。
-
左值引用
- 左值:一个表示数据的表达式,程序可获取其地址。
- 左值出现在赋值语句的左边,但修饰符的出现const使得声明的标识符,即不能给它赋值,但可获取其地址。
int n; int * pt = new int; const int b = 101; // 不能赋值, int & rn = n; int & rt = *pt; const int &rb = b; // b标识符const引用地址
-
右值引用
- C++11新增
右值引用,使用&&表示。右值引用可以关联到右值,即可出现在赋值表达式右边,但不能对其应用地址运算符的值。 右值包括:字面常量、表达式和返回值的函数(函数返回的不能是引用)。- 引入右值引用的主要目的之一:实现
移动语义。
int x = 10; int y = 23; int && r1 = 13; // 字面常量 int && r2 = x + y; // 表达式 double && r3 = std::sqrt(2.0); // 函数返回值
- C++11新增
-
常规复制构造函数- 使用
const左值引用作为参数,使得引用关联到左值实参。 - 可执行深复制
- 使用
-
移动构造函数- 使用
右值引用作为参数,将引用关联到右值实参。 - 只调整记录
- 在将所有权转移给新对象的过程中,移动构造函数可能修改其实参,意味着
右值引用参数不应是const。
- 使用
- 适用于构造函数的移动语义考虑也适用于赋值运算符。
- 原有的4个特殊成员函数
- 默认构造函数
- 复制构造函数
- 复制赋值运算符
- 析构函数
- C++新增的2个
- 移动构造函数
- 移动赋值运算符
这些成员函数是编译器在各种情况下自动提供的。
- 如果提供了
析构函数、复制构造函数或者复制赋值运算符,编译器将不会自动提供移动构造函数和移动赋值运算符。 - 如果提供了
移动构造函数或移动赋值运算符,编译器将不会自动提供复制构造函数和复制赋值运算符。
-
C++11中如果提供了
移动构造函数,所以编译器不会自动创建默认的构造函数、复制构造函数和复制赋值构造函数。可使用关键字 default显式声明方法的默认版本。class Someclass { public: Someclass(Someclass &&); Someclass() = default; Someclass(const Someclass &) = default; Someclass & operator=(const Someclass &) = default; ... };
-
关键字
delete可用于禁止编译器使用特定方法。- 也可禁止特定的转换
-
关键字
default只能用于6个特殊成员函数,但delete可用于任何成员函数。
- C++11 允许在一个构造函数的定义中使用另一个构造函数,这种方式称为
委托。
Notes::Notes(int kk,double xx) : Notes(kk,xx,"Uh") {/**/}-
C++98 使用
名称空间中函数可用的方式。 -
C++11 中使用
派生类继承基类的所有构造函数(默认构造函数、复制构造函数和移动构造函数除外),但不会使用与派生类构造函数的特征标匹配的构造函数。
-
在C++11中,可使用
虚说明符override指出要覆盖一个函数,将其放在参数列表后面。如果声明与基类方法不匹配,编译器将视为错误。 -
final说明符:禁止派生类覆盖特定的虚方法,所以在参数列表后面加上final。 -
override和final并非关键字,而是具有特殊含义的标识符。
Lambda 函数,也叫做Lambda表达式。
匿名函数无需给出函数命名。
在C++11中,对于接受函数指针或者函数符的函数,可使用匿名函数定义作为其参数。
匿名函数与函数的区别:
- 使用
[]替代函数名 没有声明返回类型(返回类型相当于使用decltype根据返回值推断得到)- 如果
lambda不包含返回语句,推断出的返回类型将为void。
[] (int x) {return x % 3 == 0;}当且仅当, lambda表达式完全由一条返回语句组成时,自动类型推断才管用。否则,需要使用新增的返回类型后置语法:
[] (double x)-> double{int y = x; return x - y;} // 返回类型为double四个角度来分析
- 距离
- 函数定义离使用地点近。
- 简洁
- 函数符代码比函数和lambda代码更繁琐。
- 效率
- 三种方式的相对效率取决于编译器内联。
- 功能
- lambda可访问
作用域内的任何动态变量 - 要捕获使用的变量,可将其名称放在中括号内。
- 如果
只指定变量名,如[z],则将值访问变量 - 如果在
名称前加上 &,如[&count],则按引用访问变量
- 如果
[&]按引用访问所有动态变量[=]按值访问所有动态变量。
- lambda可访问
函数指针方法阻止内联,因为编译器传统上不会内联其他地址被获取的函数,因为函数地址的概念意味着非内联函数。而函数符和lambda通常不会阻止内联。
可以给lambda指定一个名称,然后使用名称来替代。
auto mod3 = [] (int x) {return x % 3 == 0;} // mod3 a name for the lambda
count1 = std::count_if(n1.begin(),n1,end(),mod3);
count2 = std::count_if(n2.begin(),n2.end(),mod3);C++中引入lambda的主要目的:能将类似于函数的表达式用做接受函数指针或函数符的函数的参数。
C++提供多个包装器(wrapper,也叫做适配器(adapter))。
C++11中提供了其他的包装器:
bind- 可替代
bind1st和bind2nd
- 可替代
mem_fn- 可将成员函数作为常规函数进行传递
reference_wrapper- 能创建行为像引用但可被复制的对象
function- 以统一的方式处理多种类似于函数的形式
模板function 是在头文件functional 中声明,从调用特征标的角度定义了一个对象,可用于包装调用特征相同的函数指针、函数对象或者lambda表达式。
// 接受一个char参数和一个int参数,并返回一个double值的任何函数指针、函数对象或者lambda表达式赋值给它
std::function<double>(char, int) > fdci;要创建可变参数模板,需要理解以下要点:
- 模板参数包(parameter pack)
- 函数参数包
- 展开参数包
- 递归
C++11中提供省略号表示的元运算符(meta-operator)。
模板参数包:可以声明表示模板参数包的标识符,模板参数包是一个类型列表。函数参数包:可以声明表示函数参数包的标识符,函数参数包是一个值列表。
// Args可以与任意数量的类型匹配
template <typename... Args> // Args 是模板参数包
void show_list(Args...args) // args 是函数参数包
{
...
}将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,以此类推,直到列表为空。
template <typename T ,typename...Args>
void show_list(T value, Args..args)
{
show_list(args...);
}
// 对于按值传递来说,效率低,所以可更改为;
void show_list1(const T& value, const Args&... args)
{
show_list1(args...);
}为解决并行性的问题,C++定义了一个支持线程化执行的内存模型,添加了关键字 thread_local ,提供了相关库支持。
关键字 thread_local 将变量声明为静态存储,其持续性和特定线程相关,即定义变量的线程过期时,变量也过期。
库支持由原子操作(automic、operation)库和线程支持库组成。原子操作库提供的头文件:
threadmutexconditionvariablefuture
在C++11中新增专用的头文件库
- random:随机数扩展工具
- chrono:处理时间间隔的途径
- tuple:支持模板tuple。
- ratio:编译阶段的有理数算术库
- regex:正则表达式库。用于指定与文本字符串的内容匹配。
低级编程中的“低级”指的是抽象程度,而不是编程质量。
C++11给低级编程人员提供的两个便利:
- 放松了
POD(Plain Old Data)的要求。 - 允许
共用体的成员有构造函数和析构函数。