“C++ Primer”
关联容器
标准库提供 8 个关联容器,他们的不同体现在:
- 或者是一个
set
,或者是一个map
- 或者要求不重复的关键字,或者允许重复关键字,允许重复关键字的容器的名字中都包含单词
multi
- 按顺序保存或者无序保存,不保持关键字按顺序存储的容器的名字都以
unordered
开头
pair
定义在头文件utility
中,pair
是一个用来生成特定类型的模板,当创建一个pair
时,必须提供两个类型名
### 动态内存
##### 静态内存
静态内存用来保存局部```static```对象、类```static```数据成员以及定义在任何函数外的变量,由编译器自动分配和销毁,```static```对象在使用之前分配, 在程序结束时销毁
##### 栈内存
用来保存定义在函数内的非```static```对象,由编译器自动分配和销毁,仅在其定义的程序块运行时才存在
#### 智能指针
与常规指针的区别:负责自动释放所指向的对象
###### ```shared_ptr```
1. ```make_shared()```函数:最安全的分配和使用动态内存的方法
```c++
shared_ptr<int> p3 = make_shared<int>(42); // 指向一个值为 42 的 int 的 shared_ptr
-
shared_ptr
的拷贝和赋值每个
shared_ptr
都有一个关联的计数器,称为引用计数,无论何时我们拷贝一个shared_ptr
,计数器都会递增,如用一个shared_ptr
初始化另一个shared_ptr
,或将它作为参数传递给一个函数以及作为函数的返回值;当给shared_ptr
赋一个新值或是shared_ptr
被销毁,计数器递减一旦一个
shared_ptr
的计数器变为 0 ,它就会自动释放自己管理的对象shared_ptr
的析构函数会递减它所指的对象的引用计数,如果引用计数变为0,shared_ptr
的析构函数就会销毁对象,并释放内存
直接管理内存
new
默认情况下,动态分配的对象是默认初始化的,内置类型或组合类型的对象的值是未定义的,类类型对象将使用默认构造函数进行初始化
1
2
3
int *pi = new int; // pi 指向一个动态分配的,为初始化的无名对象
int *pi2 = new int(); // 值初始化为 0,*pi2 为0
string *ps = new string; // 初始化为空的 string
值初始化的内置类型对象有着良好定义的值,而默认初始化的对象的值则是未定义的
空悬指针
指向一块曾经保存数据对象但现在已经无效的内存的指针
智能指针陷阱
- 不使用相同的内置指针值初始化(或 reset)多个智能指针
- 不
delete get()
返回的指针 - 不使用
get()
初始化或reset
另一个智能指针 - 如果使用
get()
返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了 - 如果使用智能指针管理的资源不是
new
分配的内存,记住给它传递一个删除器
unique_ptr
一个unique_ptr
拥有它所指向的对象,与shared_ptr
不同,某个时刻只能有一个shared_ptr
指向一个给定对象,也没有make_shared
这样的标准库函数,当定义一个unique_ptr
时,需要将其绑定到一个new
返回的指针上,初始化unique_ptr
必须采用直接初始化形式
1
2
3
4
5
6
7
8
9
10
unique_ptr<double> pl;
unique_ptr<int> p2(new int(42));
unique_ptr<string> p3(new string("test"));
unique_ptr<string> p4(p3); // 错误,unique_ptr 不支持拷贝
unique_ptr<string> p5;
p5 = p3; // 错误,unique_ptr 不支持赋值
unique_ptr<string> p6(p3.release()); // 将所有权从 p3 转移给 p6, release 将 p3 置为空
unique_ptr<string> p7(new string("test"));
p4.reset(p7.release()); // 将所有权从 p7 转移给 p4, release 将 p3 置为空,并返回指针,p4 释放原来指向的内存
```c++
p2.release(); // 错误, p2 不会释放内存,而且我们丢失了指针
auto p = p2.release(); // 正确,但必须记得 delete(p)
不能拷贝unique_ptr
规则例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr
1
2
3
unique_ptr<int> clone(int p) {
return unique_ptr<int>(new int (p));
}
weak_ptr
由于对象可能不存在,不能直接使用```weak_ptr```访问对象,必须调用```lock```
#### lock
此函数检查```weak_ptr```指向的对象是否存在,如果存在,返回一个指向共享对象的```shared_ptr```
#### 动态数组
1. ```new```和数组
```c++
int *pia = new int[get_size()]; // 方括号中必须是整型但不必是常量
##### 智能指针与动态数组
标准库提供了一个可以管理```new```分配的数组的```unique_ptr```版本,使用时需要在对象类型后加上一对空方括号
```c++
unique_ptr<int[]> up(new int[10]); // up 指向一个包含 10 个为初始化 int 的数组
-
```new```将内存分配和对象构造组合在了一起,标准库```allocator```类定义在头文件```memory```中,它帮助我们将在内存分配和对象构造分离开来,它分配的内存是原始的、未构造的 ```c++ allocator<string> alloc; // 可以分配 string 的 allocator 对象 auto const p = alloc.allocate(n); // 分配 n 个未初始化的 string auto q = p; // q 指向最后构造的元素之后的位置 alloc.construct(q++); // *q 为空字符串 alloc.construct(q++, 10, 'c'); // *q 为 cccccccccc while(q != p) alloc.destroy(--q); // 释放构造的 string alloc.deallocate(p, n); // 释放内存