String
一般不建议在接口中使用const string&
,除非确实知道调用者已经持有 string:如果函数里不对字符串做复杂处理的话,使用const char*
可以避免在调用者只有 C 字符串时编译器自动构造 string,这种额外的构造和析构成本不低。
反过来,如果实现较为复杂、希望使用 string 的成员函数的话,就应该考虑下面的策略:
- 如果不修改字符串的内容,使用
const string&
或 C++17 的string_view
作为参数类型。后者是最理想的情况,因为即使在只有 C 字符串的情况,也不会引发不必要的内存复制。 - 如果需要在函数内部修改字符串内容、但又不影响调用者的该字符串,使用
string
作为参数类型(自动拷贝)。 - 如果需要改变调用者的字符串内容,使用
string&
作为参数类型(通常不推荐)。
vector
当内存重分配,或者元素位置移动时,vector 通常保证强异常安全性,如果元素类型没有提供一个保证不抛异常的移动构造函数,vector 通常会使用拷贝构造函数。
因此,对于拷贝代价较高的自定义元素类型,我们应当定义拷贝构造函数,并标记其为noexcept
,或只在容器中放置对象的智能指针。
deque
deque 中的元素只是部分连续的,因此没法提供data
成员函数。
每一段存储的大小相等,deque 支持使用下标访问容器元素,大致相当于index[i/chunk_size][i%chunk_size]
。
list
C++中的 list 代表双向链表。
某些标准算法在 list 上会出问题,list 提供了成员函数作为替代。
1 | list<int> lst{1, 7, 2, 8, 3}; |
forward_list
单向链表。
queue
它不是完整的实现,而是依赖于某个现有的容器,被称为容器适配器。
queue 缺省用 deque 来实现。
stack
stack 缺省也是用 deque 来实现,但它的概念和 vector 更相似。
扩展
Q: 为什么stack(或 queue)的 pop 函数返回类型为 void,而不是直接返回容器的 top(或 front)成员?
A: 为保证强异常安全性,如果元素类型没有提供一个保证不抛出异常的移动构造函数,通常会使用拷贝构造函数。而 C++98 还没有移动构造的概念,所以如果返回成员,就必须使用拷贝构造函数,这时候分配空间可能出错,导致构造失败,要抛出异常。因此没必要返回成员。