Effective STL读书笔记
没有c++程序不使用STL,这是一本讲述如何正确高效地使用STL的参考书。
STL的核心是容器和算法,有了一定的使用经验之后,本书可以作为技术提升的点睛之笔。
本书成文较早,技术已经发生了较大的变化,取其精华。
容器
- 慎重选择容器类型。
- 标准STL序列容器:vector, string, deque, list。
- 标准STL关联容器:set, multiset, map, multimap。
- 非标准序列容器:slist, rope。
- 非标准关联容器:hash_set, hash_multiset, hash_map, hash_multimap。
- vector vs string
- vector vs 标准关联容器
- 标准的非STL容器:array, bitset, valarray, stack, queue, priority_queue
- 不要试图编写独立于容器类型的代码。
- 确保容器中的对象拷贝正确而高效。要注意无处不在的拷贝。
- 使用empty()而非size()来确认容器是否为空。不用纠结,安全而可靠。
- 区间成员函数优先于与之对应的单元素成员函数。如给vector赋值时,优先使用assign而非push_back。
- 当心编译器糟糕的分析机制。
- 如果容器中包含了通过new创建的指针,记得容器析构前将指针delete掉。使用智能指针后应该没有这个问题了。
- 绝对不要创建包含auto_ptr的容器对象。考虑到容器中无处不在的复制,当然不通使用auto_ptr这种词不达意的东西。当然,auto_ptr已经废弃了。
- 慎重选择删除元素的方法。erase-remove/remove_if/remove_copy_if && swap/erase。
- 了解分配子的约定和限制。
- 理解自定义分配子的合理用法。
- 切勿对STL容器的线程安全性有不切实际的依赖。
- 多个线程读是安全的(没有写操作)。
- 多个线程对不同容器做写入操作是安全的(一个容器不会被并发写)。
vector和string
- vector和string优先于动态分配的数组。
- 使用reserve避免不必要的内存重新分配。提前分配好足够使用的内存,分清楚size, capacity, resize和reserve的区别与联系。
- 注意string实现的多样性。
- 了解如何把vector和string数据传给旧的API接口。
- 使用swap技巧去除多余的容量。
- 不要使用vector。因为它的行为不是真的bool。
关联容器
- 理解相等与等价的区别。
- 为包含指针的关联容器指定比较类型。
- 总是让比较函数在等值的情况下返回false。
- 不要直接修改set和multiset中的键。因为它们是排序的,修改会打乱这一生态。
- 考虑使用排序的vector代替关联容器。这取决于具体的使用场合。
- 当效率至关重要时,慎重选择map::operator[]和map::insert。参考c++ map实用操作。
- 熟悉非标准的hash容器。现在已经可以直接使用unordered_map了。
迭代器
- iterator优先于const_iterator/reverse_iterator/const_reverse_iterator。
- 使用distance/advance将容器的const_iterator转换为iterator。
- 正确理解由reverse_iterator的base()成员函数生成的iterator的用法。
- 对于逐个字符的输入考虑使用istreambuf_iterator。
算法
- 确保目标区间足够大。使用成员函数,如back_inserter,容器会自动扩充内存。
- 了解各种与排序有关的选择。sort/partial_sort/nth_element/stable_sort/partion/stable_partion,各有千秋。
- 如果确实要删除元素,在remove类算法之后调用erase。
- 对包含指针的容器使用remove算法时要特别小心。同样,使用智能指针吧。
- 了解要求使用排序区间作为参数的特定算法。
- 通过mismatch/lexicographical_compare实现简单的忽略大小写的字符串比较。
- 理解copy_if算法的正确实现。
- 使用accumulate或者for_each进行区间统计。
函数子、函数子类、函数及其他
- 遵循按值传递的原则来设计函数子类。
- 确保判别式是纯函数。纯爷们,知道吧?
- 若一个类是函数子,则应使它可配接。
- 理解ptr_fun/mem_fun/mem_fun_ref的由来。
- 确保less与operator<具有相同的含义。
在程序中使用STL
- 算法调用优于手写循环。如果有手写的循环了,考虑一下是否有算法可替代。
- 容器的成员函数优于同名的算法。私人定制优于大锅饭。
- 正确区别count/find/binary_search/lower_bound/upper_bound/equal_bound。
- 考虑使用函数对象而非函数作为STL算法的参数。
- 避免产生“直写型”代码。易读好懂的代码才是好代码。
- 不要忘记包含正确的头文件。
- 学会分析与STL相关的编译器诊断信息。
- 熟悉与STL相关的web站点。
参考资料
《Effective STL》