接上一篇,本篇主要是针对C++的新特性介绍,包括异常和智能指针
异常
异常函数,抛出异常用throw xxx
;
1 | // 默认情况下表示可能会抛出任何异常 |
try-catch
捕获异常
1 | try { |
throw
异常后,会在当前函数中查找匹配的catch
,找不到就终止当前函数代码,去上一层函数中查找。如果最终都找不到匹配的catch,整个程序就会终止
C++标准库提供了很多常用的异常,放在std
命名空间下,开发中可以使用这些异常,让代码语义更明确,如下
- std::exception
- std::bad_alloc
- std::bad_cast
- std::bad_exception
- std::bad_typeid
- std::logic_error
- std::domain_error
- std::invalid_argument
- std::length_error
- std::out_of_range
- std::runtime_error
- std::overflow_error
- std::range_error
- std::underflow_error
智能指针
由于函数执行的流程不可预测,异常处理
会带来内存管理的问题,C++引入智能指针解决内存管理的问题
auto_ptr
(已废弃):自动管理内存的释放1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
// 1. 创建一个auto_ptr指针变量p1,当p1释放时,"hello"也会被释放,不需要手动释放hello字符串
auto_ptr<string> *p1 = new string("hello");
// 不需要手动释放,当变量p1释放的时候(栈空间被回收),就会自动释放
// delete p1;
// 2. p1将所有权转让给p2,p1会指向nullptr,而p2指向"hello"
auto_ptr<string> p2 = p1;
}unique_ptr
:自动管理内存释放,且内存只能有一个指针变量引用,不支持赋值和复制1
2
3
4
5
6
7
8
9
10
11
12
std::unique_ptr<Task> p1(new string("hello"));
// 通过 unique_ptr 访问其成员
string *s1 = p1.get();
// 编译不通过,不能支持赋值
std::unique_ptr<Task> p2 = p1;
// 可以通过std::move转移所有权到p2,此时p1指向nullptr
std::unique_ptr<Task> p2 = std::move(p1);shared_ptr
:通过引用技术共享对象,对象内部存储引用技术,当引用技术为0的时候,则进行析构,与ObjC的ARC技术类似1
2
3
4
5
6shared_ptr<string> p1(new string("hello"));
// 引用计数为1
cout << p1.use_count() << endl;
auto p2 = p1
// 引用计数为2
cout << p1.use_count() << endl;weak_ptr
:由于shared_ptr存在循环引用的问题,weak_ptr用于弱引用对象(引用计数不加1)与strong_ptr配合使用
自己实现auto_ptr
指针,通过栈上的局部变量管理
1 | template <typename T> |
模板(泛型)
C++通过模板实现泛型,模板其实是相当于语法糖,在编译的时候自动生成对应的方法,如果方法没有使用,则不会被编译
1 | // 模板方法-单参数 |
编译细节
- 所有的
.cpp
文件都是单独编译的,编译成.obj
目标文件,而对于外部符号(例如头文件的声明的符号)都通过占位
的方式进行编译 - 编译完成后,通过链接器
linker
,链接所有的.obj
,把所有的占位符号都修复
成成真实的地址
为了解决模板编译的问题,把头文件改为.hpp
,hpp文件既包含声明也包含实现,通常用来定义模板类和模板方法
C++新特性
这里只列出一些常用的
auto
关键字:自动识别类型,和其他语言的var
差不多1
2auto person = new Person();
auto a = 10;decltype
: 编译器特性,获取变量的类型1
2
3int a = 10;
// 相当于:int b = a + 1
decltype(a) b = a + 1;nullptr
: 空指针,解决NULl
二义性问题1
2
3
4
5
6
7
8
9void func(int a) { }
void func(int *a) { }
// 存在二义性问题
func(NULL);
// 用下面方式调用
func(0);
func(nullptr);for
快速遍历1
2
3
4int items[] = {1, 2, 3};
for (auto item: items) {
...
}lambda
表达式:[capture] (params) mutable exception -> returntype { body }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37int g = 10;
int h = 20
// 捕获局部变量g,参数为int,返回值为void
void (*p)(int) = [g] (int a) -> void {
cout << a << g << endl
};
// 可以用auto,自动识别类型,用=隐式捕获用到的变量
auto p1 = [=] (int a) -> void {
cout << a << g << endl
};
// 引用捕获
auto p1 = [&g] (int a) -> void {
cout << a << g << endl
};
// 隐式引用捕获,g为值捕获
auto p1 = [&, g] (int a) -> void {
cout << a << g << endl
};
// 值捕获变量修改,添加mutable,可以修改捕获变量,修改了也还是值捕获,不会作用到外部
auto p1 = [g] (int a) mutable -> void {
g++;
cout << a << g << endl
};
// 如果能推断返回值类型,也可以返回值
auto p2 = [](int a){
cout << a << endl
return a;
};
p();
p2();