标签:操作符 load border cts 建立 绑定 优势 graph 笔记
这是《Effective STL》笔记最后一期,不能涵盖全部内容,书后仍然有些附加内容,不在附加,有兴趣可以找原书来读读,一则是区域设置后的忽略大小写比较,另一则是MSVC4-5编译器下STL注意事项
条款41:了解使用ptr_fun、mem_fun和mem_fun_ref的原因
函数和函数对象总使用用于非成员函数的语法形式调用。mem_fun带有一个到成员函数的指针,pmf,并返回一个mem_fun_t类型的对象。这是一个仿函数类,容纳成员函数指针并提供一个operator(),它调用指向在传给operator()的对象上的成员函数。mem_fun_t这样的类被称为函数对象适配器。类似的mem_fun_ref可以完成成员函数的调用。无论何时都可以使用ptr_fun完成,这两者的调用,但是会使得代码语义不明。
条款42:确定less<T>表示operator<
试图修改std里的组件确实是禁止的(而且这么做通常被认为是行为未定义的范畴),但是在一些情况下,修补是允许的。具体来说,程序员被允许用自定义类型特化std内的模板。特化std模板的选择几乎总是更为优先,但很少发生,这确实合理的。例如,智能指针类的作者经常想让他们的类在排序的时候行为表现得像内建指针,因此用于智能指针类型的std::less特化并不罕见。当然这是允许的,因为这个less的特化仅仅在排序上保证智能指针的行为与它们的内建兄弟相同。
operator<不仅是实现less的默认方式,它还是程序员希望less做的。让less做除operator<以外的事情是对程序员预期的无故破坏。如果你使用less(明确或者隐含),保证它表示operator<。如果你想要使用一些其他标准排序对象,建立一个特殊的不叫做less的仿函数类。
条款43:尽量用算法调用代替手写循环
每个算法接受至少一对用来指示将被操作的对象区间的迭代器。当算法被执行时,它们必须检查指示给它的区间中的每个元素,并且是按你所期望的方式进行的:从区间的起始点循还到结束点。所以,算法内部是一个循环。此外,STL算法的广泛涉及面意味着很多你本来要用循环来实现的任务,现在可以改用算法来实现了。
在算法调用与手写循环正在进行的较量中,关于代码清晰度的底线是:这完全取决于你想在循环里做的是什么。如果你要做的是算法已经提供了的,或者非常接近于它提供的,调用泛型算法更清晰。如果循环里要做的事非常简单,但调用算法时却需要使用绑定和适配器或者需要独立的仿函数类,你恐怕还是写循环比较好。最后,如果你在循环里做的事相当长或相当复杂,天平再次倾向于算法。因为长的、复杂的通常总应该封装入独立的函数。只要将循环体一封装入独立函数,你几乎总能找到方法将这个函数传给一个算法(通常是for_each),以使得最终代码直截了当。
条款44:尽量用成员函数代替同名的算法
有些容器拥有和STL算法同名的成员函数。大多数情况下,你应该用成员函数代替算法。这样做有两个理由。首先,成员函数更快。其次,比起算法来,它们与容器结合得更好(尤其是关联容器)。那是因为同名的算法和成员函数通常并不是是一样的。
对于标准的关联容器,选择成员函数而不是同名的算法有几个好处。首先,你得到的是对数时间而不是线性时间的性能。其次,你判断两个元素“相同”使用的是等价,这是关联容器的默认定义。第三,当操纵map和multimap时,你可以自动地只处理key值而不是(key, value)对。
list成员函数的行为和它们的算法兄弟的行为经常不相同。如果你真的想从容器中清除对象的话,调用remove、remove_if和unique算法后,必须紧接着调用erase函数;但list的remove、remove_if和unique成员函数真的去掉了元素,后面不需要接着调用erase。在sort算法和list的sort成员函数间的一个重要区别是前者不能用于list。作为单纯的双向迭代器,list的迭代器不能传给sort算法。merge算法和list的merge成员函数之间也同样存在巨大差异。这个算法被限制为不能修改源范围,但list::merge总是修改它的宿主list。
条款45:注意count、find、binary_search、lower_bound、upper_bound和equal_range的区别
你想知道的 | 使用的算法 | 使用的成员函数 | ||
无序区间 | 有序区间 | set/map | multiset/map | |
期望值是否存在 | find | binary_search | count | find |
期望值是否存在? |
find | equal_range | find |
lower_bound find |
第一个不在期望值 |
find_if | lower_bound | lower_bound | lower_bound |
第一个在期望值之 |
find_if | upper_bound | upper_bound | upper_bound |
有多少对象等于期 |
count |
equal_range 然后distance |
count | count |
等于期望值的所有 |
find(迭代) | equal_range | equal_range | equal_range |
条款46:考虑使用函数对象代替函数作算法的参数
一个关于用高级语言编程的抱怨是抽象层次越高,产生的代码效率就越低。操作包含一个double的类产生的代码效率比对应的直接操作一个double的代码低。因此你可能会奇怪地发现把STL函数对象——化装成函数的对象——传递给算法所产生的代码一般比传递真的函数高效。这个行为的解释很简单:内联。如果一个函数对象的operator()函数被声明为内联(不管显式地通过inline或者隐式地通过定义在它的类定义中),编译器就可以获得那个函数的函数体,而且大部分编译器喜欢在调用算法的模板实例化时内联那个函数。在上面的例子中,greater<double>::operator()是一个内联函数,所以编译器在实例化sort时内联展开它。结果,sort没有包含一次函数调用,而且编译器可以对这个没有调用操作的代码进行其他情况下不经常进行的优化。
还有另一个使用函数对象代替函数作为算法参数的理由,STL平台经常完全拒绝有效代码,即使编译器或库或两者都没问题。解决方式就是创建仿函数类,仿函数类的创造不仅避开了编译器一致性问题,而且可能会带来性能提升。
另一个用函数对象代替函数的原因是它们可以帮助你避免细微的语言陷阱。有时候,看起来合理代码被编译器由于合法性的原因——但很模糊——而拒绝。
条款47:避免产生只写代码
当你写代码时,它似乎很直截了当,因为它是一些基本想法(也就是,erase-remove惯用法加上使用逆向迭代器调用find的想法)的自然产物。但是,读者们很难把最后的产物分解回它基于的想法。这就被称为只写代码:很容易写,但很难读和理解。代码的读比写更经常,这是软件工程的真理。也就是说软件的维护比开发花费多得多的时间。不能读和理解的软件不能被维护,不能维护的软件几乎没有不值得拥有。你用STL越多,你会感到它越来越舒适,而且你会越来越多的使用嵌套函数调用和即时(on the fly)建立函数对象。
条款48:总是#include适当的头文件
条款49:学习破解有关STL的编译器诊断信息
举个例子:
1 string s(10); // 常识建立一个大小为10的string
这段代码是不能通过编译的,提示信息如下:
error C2664:
‘__thiscall std::basic_string<char, structstd::char_traits<char>,class std::allocator<char> >::std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > (const class std::allocator<char> &)‘: cannot convert parameter 1 from ‘const int‘ to ‘constclass std::allocator<char> &‘
Reason: cannot convert from ‘const int‘ to ‘constclass std::allocator<char>
No constructor could take the source type, or constructor overload resolution was ambiguous
string不是一个类,它是typedef。实际上,它是这个的typedef:basic_string<char, char_traits<char>, allocator<char> >。用文字“string”全局替换冗繁难解的basic_string:
error C2664:
‘__thiscall string::string(const classstd::allocator<char> &)‘: cannot convert parameter 1 from ‘const int‘ to const class std::allocator<char> &‘
就可以比较容易的看出是没有相应的参数转换,而实际上string没有传int参数的构造函数。
条款50:让你自己熟悉有关STL的网站
作者还推了一堆书,我觉得要看完估计很久,如果真的需要的话,建议去原著上面找找,这里就不发了。
《Effective STL》到此结束。
标签:操作符 load border cts 建立 绑定 优势 graph 笔记
原文地址:http://www.cnblogs.com/hellomotty/p/7455208.html