第 43 条:算法调用优先于手写的循环。
- 本条款的理由如下:
- 效率:算法通常比程序员自己写的循环效率更高。
- 正确性:自己写循环比使用算法更容易出错。
- 可维护性:使用算法的代码通常比手写循环的代码更加简洁明了。
- 算法调用和手写循环的选择思路如下:
- 如果要做的工作与一个算法所实现的功能很相近,那么用算法调用更好。
- 如果循环很简单,而若使用算法来实现的话却要求混合使用绑定器和配接器或者要求一个单独的函数子类,那么可能使用手写的循环更好。
- 如果循环中要做的工作很多而且又很复杂,则最好使用算法调用。
第 44 条:容器的成员函数优先于同名的算法。
- 有些 STL 容器提供了一些与算法同名的成员函数。【算法和成员函数虽然有同样的名称,但是它们所做的事情往往不完全相同】
- 如关联容器提供了
count
、find
、lower_bound
、upper_bound
和equal_range
;【相比非成员函数版本,它们保证对数时间的性能】 - 如
list
则提供了remove
、remove_if
、unique
、sort
、merge
和reverse
。【避免拷贝list
元素】- 例如
remove
函数和list::remove
函数的区别:非成员函数版本remove
想要真正删除元素,只能使用erase
+remove
;list
的成员函数版本remove
是真正删除节点】 - 例如
sort
函数和list::sort
函数的区别:非成员函数版本sort
无法应用到list
容器,因为list
的迭代器是双向迭代器,而sort
算法要求随机访问迭代器。 - 例如
merge
函数和list::merge
函数的区别:非成员函数版本merge
算法是不允许修改其源区间的;而list::merge
则总是在修改它所操作的链表。
- 例如
- 如关联容器提供了
- 该条款的理由:
- 第一,成员函数往往速度快;
- 第二,成员函数通常与容器(特别是关联容器)结合得更加紧密。
第 45 条:正确区分 count、find、binary_search、lower_bound、upper_bound 和 equal_range。
- 在选择具体的查找策略时,由迭代器指定的区间是否是排序的,这是很重要的条件。
- 如果区间是排序的,那么通过
binary_search
、lower_bound
、upper_bound
和equal_range
,你可以获得更快的查找速度(通常是对数时间的效率)。 - 如果迭代器并没有指定一个排序的区间,那么你的选择范围将局限于
count
、count_if
、find
以及find_if
,而这些算法仅能提供线性时间的效率。
- 如果区间是排序的,那么通过
第 46 条:考虑使用函数对象而不是函数作为 STL 算法的参数。
- 在 C/C++ 中并不能真正地将一个函数作为参数传递给另一个函数;如果我们试图将一个函数作为参数进行传递,则编译器会隐式地将它转换成一个指向该函数的指针,并将该指针传递过去。【函数指针参数抑制了内联机制】
- 以函数对象作为 STL 算法的参数,这种做法提供了包括效率在内的多种优势。
- 从代码被编译器接受的程度而言,它们更加稳定可靠。
- 普通函数在 C++ 中也是非常实用的,但是就有效使用 STL 而言,函数对象通常更加实用一些。
第 47 条:避免产生“直写型”(write-only)的代码。
- 当你编写代码的时候,它看似非常直接和简捷,因为它是由某些基本想法(比如,
erase
+remove
习惯用法加上在find
中使用reverse_interator
的概念)自然而形成的。- 又或者指一行代码中有过于复杂的嵌套函数调用,可能对于编写代码的人,这行代码看似非常直接和简单,但是对于阅读代码的人则显得难以理解。
- 在遇到这种写出“直写型”代码时,应该将其拆分成多行代码,或者使用
typedef
起别名的形式,让代码更易于阅读。
第 48 条:总是包含(#include)正确的头文件。
- C++ 标准与 C 的标准有所不同,它没有规定标准库中的头文件之间的相互包含关系。
- 有的时候即使漏掉了必要的头文件,程序同样可以编译;因为某个头文件包含了其他头文件,如
<vector>
包含了<string>
。 - 但是这种程序往往是不可移植的,即使在你的平台上可以编译,但是在其他平台上就可能会编译不过,所以解决此类问题的一条原则就是总是
include
必要的头文件。
- 有的时候即使漏掉了必要的头文件,程序同样可以编译;因为某个头文件包含了其他头文件,如
- 总结每个与 STL 有关的标准头文件中所包含的内容:
- 几乎所有的标准 STL 容器都被声明在与之同名的头文件中,比如
vector
被声明在<vector>
中,list
被声明在<list>
中;但是<set>
和<map>
是个例外,<set>
中声明了set
和multiset
,<map>
中声明了map
和multimap
。 - 除了四个 STL 算法以外,其它所有的算法都被声明在
<algorithm>
中,这四个算法是accumulate
、inner_product
、adjacent_difference
和partial_sum
,它们被声明在头文件<numeric>
中。 - 特殊类型的迭代器,包括
istream_iterator
和istreambuf_iterator
,被声明在<iterator>
中。 - 标准的函数子(比如
less<T>
)和函数子配接器(比如not1
、bind2nd
)被声明在头文件<functional>
中。
- 几乎所有的标准 STL 容器都被声明在与之同名的头文件中,比如
第 49 条:学会分析与 STL 相关的编译器诊断信息。
- 在程序编译或者运行出错时,有时编译器给出的诊断信息非常混乱和难以阅读。
- 对于这些信息可以使用同义词替换的方法进行简化,比如说将
std::basic_string<>
替换成string
,将std::map<>
替换成map
,将看不懂的 STL 内部模板std::_Tree
替换成something
。
第 50 条:熟悉与 STL 相关的 Web 站点。
- 三个 STL 相关网站:
- SGI STL 网站,http://www.sgi.com/tech/stl/。
- STLport 网站,http://www.stlport.org/。
- Boost 网站,http://www.boost.org/。(或者 http://boost.sourceforge.net/)