【读书笔记】【Effective STL】在程序中使用 STL

第 43 条:算法调用优先于手写的循环。

  • 本条款的理由如下:
    • 效率:算法通常比程序员自己写的循环效率更高。
    • 正确性:自己写循环比使用算法更容易出错。
    • 可维护性:使用算法的代码通常比手写循环的代码更加简洁明了。
  • 算法调用和手写循环的选择思路如下:
    • 如果要做的工作与一个算法所实现的功能很相近,那么用算法调用更好。
    • 如果循环很简单,而若使用算法来实现的话却要求混合使用绑定器和配接器或者要求一个单独的函数子类,那么可能使用手写的循环更好。
    • 如果循环中要做的工作很多而且又很复杂,则最好使用算法调用。

第 44 条:容器的成员函数优先于同名的算法。

  • 有些 STL 容器提供了一些与算法同名的成员函数。【算法和成员函数虽然有同样的名称,但是它们所做的事情往往不完全相同】
    • 如关联容器提供了 countfindlower_boundupper_boundequal_range;【相比非成员函数版本,它们保证对数时间的性能】
    • list 则提供了 removeremove_ifuniquesortmergereverse。【避免拷贝 list 元素】
      • 例如 remove 函数和 list::remove 函数的区别:非成员函数版本 remove 想要真正删除元素,只能使用 erase + removelist 的成员函数版本 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_searchlower_boundupper_boundequal_range,你可以获得更快的查找速度(通常是对数时间的效率)。
    • 如果迭代器并没有指定一个排序的区间,那么你的选择范围将局限于 countcount_iffind 以及 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 有关的标准头文件中所包含的内容:
    1. 几乎所有的标准 STL 容器都被声明在与之同名的头文件中,比如 vector 被声明在 <vector> 中,list 被声明在 <list>中;但是 <set><map> 是个例外,<set> 中声明了 setmultiset<map> 中声明了 mapmultimap
    2. 除了四个 STL 算法以外,其它所有的算法都被声明在 <algorithm> 中,这四个算法是 accumulateinner_productadjacent_differencepartial_sum,它们被声明在头文件 <numeric> 中。
    3. 特殊类型的迭代器,包括 istream_iteratoristreambuf_iterator,被声明在 <iterator> 中。
    4. 标准的函数子(比如 less<T>)和函数子配接器(比如 not1bind2nd)被声明在头文件 <functional> 中。

第 49 条:学会分析与 STL 相关的编译器诊断信息。

  • 在程序编译或者运行出错时,有时编译器给出的诊断信息非常混乱和难以阅读。
  • 对于这些信息可以使用同义词替换的方法进行简化,比如说将 std::basic_string<> 替换成 string,将 std::map<> 替换成 map,将看不懂的 STL 内部模板 std::_Tree 替换成 something

第 50 条:熟悉与 STL 相关的 Web 站点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值