Effective STL 第二章-vector和string

介绍了条款13~条款18

Posted on April 18, 2018 in Effective_STL, ReadBook

[TOC]

# 条款13-vector和string优先于动态分配的数组

由于管理内存的麻烦:如防止内存泄漏,单个对象与数组的`new/delete`不匹配,`delete`多次等问题,推荐使用`vector`代替数组,而用`string`代替`char*`

一个特例:`string`是使用引用计数的,在多线程下,可能避免内存分配和字符拷贝所节省下来的时间还比不上花在背后同步控制上的时间。于是乎,可以使用`vector<char>`代替,因为`vector`不使用引用计数技术。

# 条款14-使用reserve来避免不必要的重新分配

- `resize`改变的是`size`,用了`resize`之后,容器里面是有默认元素的。

- `reserve`改变的是`capacity`,不会默认在里面放入元素,只是预先分配空间,免去不必要的拷贝。VS6.0在扩展`capacity`的时候是2倍,VS2005是1.5倍。2倍是不可理的,因为无法使用前面已有的空间。

- `resize()`函数的参数n如果比之前的`size()`要小,则尾部元素会析构,若要大,则创建新的默认元素放在容器末尾。`reserve()`函数的参数n如果比之前的`capacity()`要小,则什么都不做,因此去除多余容量可以参考条款17。

- 为什么插入操作会让迭代器,指针,引用失效呢:因为插入操作可能会导致空间重新分配,就是说,会申请新空间——将旧空间内容拷贝过来——删除旧空间上的元素——释放旧空间。于是乎,迭代器等就失效了。

# 条款15-注意`string`实现的多样性

- `string`通常包含大小size,容量capacity,与值char* val。此外还可能有分配子的一份拷贝,引用计数。

- P56 `string`的四种实现。

- 不同的实现,`sizeof(string)`的返回值不同,很可能是指针大小的1到7倍(短子串优化)。

- 不同的实现,动态分配内存的次数不同。

# 条款16-了解如何把`vector`和`string`数据传给旧的API

- 如何变指针:`vector v; &v[0] or &*v.begin()`; `string s; s.c_str()`。

- 不能用`v.begin()`代替指针。

- `string`不一定存储在连续的内存中,也不一定使用空字符结尾,因此使用`c_str()`函数。

- 实际上,可以通过vector作为沟通其他容器与C API的中介

# 条款17-使用“swap技巧”除去多余的容量

在C11中已经有`shrink_to_fit()`函数了,如果没有,可以:

“`

vector<Contestant>(contestant).swap(contestants);

“`

利用拷贝构造出来的临时变量来进行`swap()`操作,临时变量的size=capacity,由于某些编译器规定容量必须是2的幂次方,因此不一定size=capacity

而`reserve`不能shrink_to_fit详见条款14

# 条款18-避免使用`vector<bool>`

因为这个不是一个STL容器,因为`vector<bool>`的实现是存储紧凑的,只存一个位,执行`vector<bool> v; bool *pd = &v[0];`是不能编译的,因此`vector<bool>`不是STL容器。

解决办法:使用`deque<bool>`一个元素用1字节来存储;使用bitset。

在这里介绍一个概念:**代理对象**,`vector<bool>::operator[]`返回的是一个对象,这个对象表现得像是一个指向单个位的引用,因此`&v[0]`是`vector<bool>::reference*`类型而不是`bool*`类型