0%

C++11新特性

C++11 新特性笔记

初始化列表

C++11 添加了 initializer_list 类型,允许使用 initializer_list 初始化对象

STL 容器例如 map, vector 等都实现了 initalizer_list constructor

自定义的对象也可以使用 initalizer_list 作为构造函数的参数

1
2
3
4
5
6
7
8
9
10
11
vector<int> v = {1, 2, 3};

class MyVector
{
private:
std::vector<int> v_;
public:
MyVector(const std::initializer_list<int> &v) {
for (auto a : v) v_.push_back(a);
}
};

统一初始化

C++03 中,可以使用集合初始化

1
2
3
4
5
struct A{
int x;
float y;
};
A a = {1, 2.0};

C++11 允许通过同样的方式调用构造函数

1
2
3
4
5
6
struct A{
int x;
float y;
A(int x, float y) {/* Do something */}
};
A a = {1, 2.0};

连同初始化列表,统称为统一初始化

统一初始化调用顺序优先级:

  1. initalizer_list constructor
  2. 构造函数
  3. 集合初始化

auto

非常实用的功能, 从复制操作的右值直接推断变量类型

1
2
auto a = 1;
auto b = 2.0;

在 C++03 中,一个痛点:要迭代一个容器,需要

1
for(std::set<int>::iterator it = map.begin(); it != map.end(); ++it) {/* Do something */}

在 C++11 中,可以直接使用 auto

1
for(auto it = map.begin(); it != map.end(); ++it) {/* Do something */}

基于范围的for循环

对于任何一个带有 begin() 和 end() 方法的对象,例如 vector

1
2
vector<int> v = {1, 2, 3};
for (int i: v) {cout << i << endl;}

配合 auto 使用效果更佳

nullptr

在 C++03 中, 使用 NULL 代表空指针, NULL 被定义为 0, 有时候会有歧义

在 C++11 中, 使用专门的 nullptr 代表空指针, 用以解决以下问题

1
2
3
4
5
6
7
void func(int i) {}
void func(char* p) {}

int main() {
func(NULL); // 有歧义, 编译器报错
func(nullptr); // C++11, 调用 func(char* p)
}

强类型枚举

C++03 中,枚举常量被暴露在同一作用域中,且被隐式转化为整形

1
2
3
enum Color{red, blue};
enum Animal{dog, cat};
red == dog // True!!

C++11 引入了 enum class 解决这个问题

1
2
3
enum Color{red, blue};
enum Animal{dog, cat};
Color::red == Animal::dog // 编译器报错,Color 和 Animal 不可比较

静态断言

C++11 允许使用 static_assert 在编译期执行断言

1
2
assert(myPointer != nullptr); // 运行期断言
static_assert(sizeof(int) == 4); // C++11 新增, 编译期断言

委托构造函数

在 C++03 中,如果两个构造函数都需要执行相同的操作,只能

1
2
3
4
5
6
class A {
init() {/*Do something*/}
public:
A() {init();}
A(int a) {init(); /* Do something with a */}
};

额外定义的 init() 函数可能被误调用

C++11 则允许在构造函数开头调用另一个构造函数, 也允许在声明时初始化成员变量

1
2
3
4
5
6
7
class A {
private:
int x = 1; // C++11 新增, 任意构造函数都会初始化 x = 1
public:
A() {/* Do something */}
A(int a): A() {/* Do something with a */}
};

Override

C++11 引入了 override 关键字,避免继承时错误的创造新函数

1
2
3
4
5
6
7
8
class A {
virtual void a(int);
};

class AA: public A {
virtual void a(float); // 创建一个新函数
virtual void a(float) override; // 编译期报错
};

final

C++11 引入 final 关键字,用于修饰类和虚函数,表示不允许继承/重载

1
2
3
4
5
6
7
class Dog final {    // Dog 不可继承
...
};

class Dog {
virtual void bark() final; // bark() 不可重载
};

默认构造函数

C++11 允许使用 default 关键字,由编译器自动生成默认构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
// C++03
class Dog {
public:
dog(int age) {} // 不会生成默认构造函数
};
Dog dog; // 编译器报错

// C++11
class Dog {
public:
dog(int age) {}
dog() = default; // 编译器自动生成默认构造函数
};

被删除的函数

C++03 中, delete 关键字仅用于释放动态分配的内存

C++11 允许使用 =delete 将函数标记为被删除的, 可以用来阻止隐式类型转换等

1
2
3
4
5
6
7
class Dog {
public:
dog(int age) {}
dog(double) = delete;
};
Dog(1);
Dog(2.0); // 编译器报错

constexpr

C++11 中, constexpr 扩展了原有 const 的用法, 允许在编译期对作用于常量的函数求值

1
2
3
4
5
constexpr int a() {return 3;}
int A[a() + 3]; // 等价于 int A[6];

constexpr int cubed(int a) {return a * a * a;}
int b = cubed(2); // 编译期求值, b = 8

字符串字面量

C++11 引入了更多的字面量定义方式,方便定义 unicode 字符串以及正则表达式等

1
2
3
4
const char    *a = u8"你好"; // UTF-8
const char16_t *b = u"你好"; // UTF-16
const char32_t *c = U"你好"; // UTF-32
const char *d = R"(\n\t)"; // raw string, 括号内不转义,配合正则表达式特别有用

lambda 函数

C++11 引入了 lambda function,方便定义匿名函数

1
2
3
4
5
auto f = [](int x, int y){return x + y;};
cout << f(1, 2) << endl; // 输出 3

vector<int> v{2,1,3};
sort(v.begin(), v.end(), [](int a, int b){return a > b;}); // v = {3, 2, 1}