1 常用特性
1.1 新类型
整形
- long long
- unsigned long long
字符型
- char16_t 支持16位字符表示
- char32_t 支持32位字符表示
1.2 初始化
(1)初始化列表
扩大了使用 { } 初始化列表的应用范围,可以用于所有内置类型和用户定义的类型。
short words[5] {1,2,3,4,5};
int a = {3};
创建对象时可以利用 { } 括起来的列表调用构造函数。
(2)防止缩窄转换
利用初始化列表编译器可以防止进行缩窄转换,相较于之前的操作具有更好的安全性。
但是允许转换为更宽的类型。
(3)std::initializer_list
initializer_list可用作构造函数的参数,属于STL模板型,具有begin()和end()操作。
可以作为函数的参数(除了构造函数外还可以用于普通函数)。
// Constructor function
vector<int> a{1, 2, 3}; //3 elements set to 1,2,3
// Function paraments of general function
int main() {
double total = sum({1, 2, 3, 4});
}
double sum(std::initializer_list<int> i) {
// Here can use begin() and end() to operator ...
}
1.3 声明
(1)auto
自动类型推断
(2)decltype
将变量的类型声明为表达式的类型。
// a same type as x*y.
decltype (x*y) a;
(3)using =
别名创建和声明。
using 具有和 typedef 同样的作用,均可以对复杂的标志符创建较为简单的别名。且using可用于模板部分具体化,但typedef没有给作用。
typedef std::vector<std::string>::iterator itType;
using itType = std::vector<std::string>::iterator;
template<typename T>
using arr = std::array<T, 12>;
// 旧语法的具体化模板
std::array<std::string, 12> a1;
std::array<double, 12> a2;
// 新语法模板具体化
arr<std::string> a1;
arr<double> a2;
(4)nullptr
nullptr表示空指针,不同于旧版本的NULL。
(5)返回类型后置
template<typename T, typename U>
auto func(T t, U u) -> decltype(T*U)
{
... 返回类型为 T*U
}
可以有效解决当编译器刚开始遇到func时并没有局部变量T和U,所有不知道返回类型,在后面使用了返回类型后置和decltype之后可以有效的额解决该问题。
1.4 智能指针
unique_ptr
shared_ptr
weak_ptr
所有的智能指针均可以和STL的移动语义协同工作。
1.5 作用域内枚举
使用了 class 和 struct 定义。同时需要显式限定,避免冲突。
作用域内枚举可以在作用域内有相同的枚举子集,只要通过显式的限定就可以避免冲突,叫之前标准更加的灵活和安全。
1.6 类的修改
(1)显示构造函数转换
explicit用于禁止单参数构造函数导致的自动转换。
通过explicit修饰后只能显示转换(也就是构造函数只能传入和声明的参数类型一样的值)。
(2)类内成员初始化
新标准可以在类的内部对成员进行初始化(成员函数和成员变量)。
class TEST
{
int var1 = 10;
double var2 {124.23};
int var3;
public:
TEST() {}
TEST(int s) : var3(s) {}
}
1.7 模板和STL的修改
(1)基于范围的for循环
(2)新的STL容器
- forward_list 单向链表,list为双向链表
- unordered_map
- unordered_multimap
- unordered_set
- unordered_multiset
- array 固定长度,不能修改容器的大小。
(3)新的STL方法
- cbegin() 指向容器第一个元素的后面,视元素为const。
- cend()
- crbegin()
- crend()
(4)valarray/export/尖括号
1.8 右值引用
传统引用称为左值引用,使得标识符关联到左值。左值是一个表示数据的额表达式,程序可以获取其地址,但是const修饰后,使得不能赋值,但是可以获取地址。
右值引用使用 && 表示,右值引用可以关联到右值,可以出现在赋值表达式右边,但不能对其应用地址运算符的值。右值包括字面常量、表达式及返回值的函数。
右值引用主要目的:实现移动语义。
2 移动语义与右值引用
移动语义(move semantics),指在数据复制过程中将实际文件依旧留在原来的地方,而只是修改记录。从而避免了移动原始数据。
区别项目 | 复制构造函数 | 移动构造函数 |
---|---|---|
复制方式 | 采用深复制,会移动原始数据。 | 不进行深复制,只调整记录 |
函数参数 | 使用const左值作为参数 | 使用右值引用作为参数 |
。。。page656
3 类的新功能
3.1 特殊成员函数
默认构造函数:没有任何参数时调用默认构造函数。
复制构造函数:没有提供但需要复制构造时,编译器会提供默认复制构造函数(下同)。
复制赋值运算符
析构函数
移动构造函数:C++11新增
移动赋值运算符:C++11新增
// 复制构造函数
Classname::Classname(const Classname &);
// 移动构造函数
Classname::Classname(Classname &&);
// 默认复制运算符
Classname & Classname::operator(const Classname &);
// 默认移动运算符
Classname & Classname::operator(Classname &&);
3.2 默认方法和禁用方法
default 可以显式地声明类方法的默认版本。
delete 可以禁止特定的转换。(比如禁止复制构造函数等)
class Someclass
{
public:
void redo(double);
void redo(int) = delete;
...
};
Someclass sc;
sc.redo(5);
如果没有delete修饰的构造函数这一行,则在调用sc.redo(5)时,int值5将会被转换为double类型的5.0,进而执行redo();
有了delete修饰的构造函数之后,在调用时由于redo(int)被禁用,所以编译器会出现编译错误。
3.3 委托构造函数
委托:在一个构造函数的定义中使用另一个构造函数被称为委托。
构造函数将创建对象的工作委托给另一个构造函数。
3.4 继承构造函数
让派生类能够继承基类构造函数,称为继承。
4 Lambda函数
4.1 函数指针,函数符,Lambda函数
4.2 为何使用Lambda函数
5 包装器
5.1 包装器function及模板的低效性
5.2 修复问题
6 可变参数模板
7 C++11新增其他功能
7.1 并行编程
7.2 低级编程
7.3 杂项
(1)字面量运算符(literal operator),可定义二进制字面量,例如1001001b。
(2)调试工具与断言
assert,运行阶段对断言进行检查,如果为true则显示一条消息,否则调用abort()。
static_assert,可用于编译阶段对断言进行测试。
断言,简单讲是程序员在某个阶段认为正确的东西。
(3)加强元编程(metaprogramming)支持。可以创建或者修改其他程序,包括自己。