前言
STL在C++开发中的重要性无需多言。它设计精妙,性能卓越,功能方便。
大多数时候,它都易于使用。但利刃能开几分光,还要依赖使用者的修养。提修养,多读书。《Efficient STL》中给出了关于STL的50条建议。
这些规则分为以下七个部分:
-
$\color{blue}{【Container(容器)】}$
-
$\color{blue}{【vector\&string(列表和字符串)】}$
-
$\color{blue}{【associate container(关联型容器)】}$
-
$\color{blue}{【Iterator(迭代器)】}$
-
$\color{blue}{【Algorithms(算法)】}$
-
$\color{blue}{【Function(函数)】}$
-
$\color{blue}{【编码实践】}$
本文将介绍vector&string, associate container两部分的内容。希望它们提供快如闪电的性能,同时照亮使用过程中的疑惑。
vector & string
使用vector和string可以省去管理内存的麻烦;string通常会维护reference记数,如果它成为多线程模式下的性能瓶颈,可以使用std::vector[HTML_REMOVED]代替
vector中的内存空间是连续的,如果向C的API传参,可以直接取vector的第一个元素:
std::vector<T> vec;
void api(const T* a, int size);
// 向api传参:
api(&(vec[0]), int(vec.size()));
容器分配内存时可以使用reserve减少扩容时的损耗;
不要使用std::vector[HTML_REMOVED],它实际上是以bit来表示bool,而且也不是STL容器之一;deque[HTML_REMOVED]和bitset可以代替;
使用reserve + swap减少重分配的损耗;swap后迭代器不会失效;
constentants.reserve(big_num);
// add number here
vector<Contestant>(contestants).swap(contestants);
Associate Container
std::find接口使用的是equal比较,对应的运算符是==;set::insert, map::insert等接口使用的则是equivalence, 对应的运算符是<
如果定义的关联容器存储的是指针类型,那么它默认将会按照指针的大小排序;如果要让它按照值的大小 排序,需要指定compare函数
如下是定义了一个string*的例子
typedef set StringPtrSet; // string set
struct StringPtrLess: public binary_function {
booI operator() (const string *psl, const string *ps2) const
{ return *psl < *ps2; }
}'
compare function必须是<, equal的时候务必返回false
关于关联容器的key:对map,multimap来说,element的类型是pair[HTML_REMOVED],K的值无法直接更改;set和multiset的类型则是T,可以更改;在一些STL的实现中,如果使用iterator,它可能返回一个const指针,禁止用户修改;如果确实需要修改set中非key的部分,比如一个struct中非key的其他字段,需要使用const_cast显性表示;不过最好的办法是删除后重新插入;
EmpIDSet::iterator i = se.find(selectedID);
// 有可能编译不过,因为i可能会返回const指针
if (i != se.end()) {
i->setTitle("Corporate Deity");
}
// 可以work的代码,注意cast类型需要是引用,而不是对象本身
if (i != se.end()) {
const_cast<Employee&>(*i).setTitle("Corporate Deity");
}
EmpIDSet::iterator i = se.find(selectedID);
// 有可能编译不过,因为i可能会返回const指针
if (i != se.end()) {
Employee e(*i); //拷贝
se.erase(i++);
e.setTitle("Corporate Deity");
se.insert(i, e);
}
如果执行的是插入大量数据,然后查找的话,可以用排序过的数组代替关联容器;它的优势在于存储空间的overhead小,localization性能更好;查找可以使用binary_search或者lower_bound
[]和insert都可以完成addOrUpdate操作;插入新元素时,insert更为高效;update的时候,[]更为高效
与STL兼容的hashmap通常具有如下定义:
template <typename T,
typename HashFunction,
typename CompareFunction,
typename Allocator = allocator<T>
>
class hash_container;
它使用equal作为比较函数;