Effective STL

2023-11-02

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcpwxQhi-1585901574462)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896080697.png)]

条款21: 永远让比较函数对相等的值返回false

set<int, less_equal > s; // s以“<=”排序
s.insert(10); // 插入10
现在尝试再插入一次10:
s.insert(10);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79gWak6T-1585901574463)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896126672.png)]

结果当然是false。 也就是说,set得出的结论是10A与10B不等价,因此不一样,于是它将10B插入容器中10A的
旁边。在技术上而言,这个做法导致未定义的行为,但是通常的结果是set以拥有了两个为10的值的拷贝而告
终,也就是说它不再是一个set了。通过使用less_equal作为我们的比较类型,我们破坏了容器!此外,任何对
相等的值返回true的比较函数都会做同样的事情。是不是很酷?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbUVhZGn-1585901574465)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896146821.png)]

相等的值绝不该一个大于另一个,所以比较函数总应该对相等的值返回false。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HzTaDNOG-1585901574466)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896189387.png)]

条款22:避免原地修改set和multiset的键

正如所有标准关联容器,set和multiset保持它们的元素有序,这些容器的正确行为
依赖于它们保持有序。 如果你改了关联容器里的一个元素的值(例如,把10变为1000),新值可能不在正确
的位置,而且那将破坏容器的有序性。很简单,是吗?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5CgYQWcT-1585901574468)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896440094.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j78woIxX-1585901574470)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896457880.png)]

只是改变雇员的一个与set排序的方式无关的方面(一个雇员的非键部分),所以这段代码不
会破坏set。

本条款的目的是提醒你如果你改变set或
multiset里的元素, 你必须确保不改变一个键部分——影响容器有序性的元素部分。如果你做了,你会破坏容
器,再使用那个容器将产生未定义的结果, 而且那是你的错误。另一方面,这个限制只应用于被包含对象的
键部分。对被包含元素的所有其他部分来说,是开放的:随便改变!

也就是怎样做才能既正确又可移植。它不难,但是它用到了太多程序员忽略的一个细节:你必须映
射到一个引用。

它们错的原因也相同。在运行期,它们不能修改i!在这两个情
况里,映射的结果是一个
i副本的临时匿名对象,而setTitle是在匿名的物体上调用,不在*i上!*i没被修改,
因为setTitle从未在那个对象上调用,它在那个对象的副本上调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1llSmc3K-1585901574471)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896576986.png)]

条款23:考虑用有序vector代替关联容器

当需要一个提供快速查找的数据结构时,很多STL程序员立刻会想到标准关联容器:set、multiset、map和
multimap。直到现在这很好,但不是永远都好。如果查找速度真得很重要,的确也值得考虑使用非标准的散
列容器(参见条款25)。如果使用了合适的散列函数,则可以认为散列容器提供了常数时间的查找。(如果
选择了不好的散列函数或表的太小,散列表的查找性能可能明显下降,但在实际中这相对少见。)对于多数
应用,被认为是常数时间查找的散列容器要好于保证了对数时间查找的set、map和它们的multi同事。
即使你需要的就只是对数时间查找的保证,标准关联容器仍然可能不是你的最佳选择。和直觉相反,对于标
准关联容器,所提供的性能也经常劣于本该比较次的vector。如果你要有效使用STL,你需要明白什么时候和
怎么让一个vector可以提供比标准关联容器更快的查找。
标准关联容器的典型实现是平衡二叉查找树。一个平衡二叉查找树是一个对插入、删除和查找的混合操作优
化的数据结构。换句话说,它被设计为应用于进行一些插入,然后一些查找,然后可能再进行一些插入,然
后也许一些删除,然后再来一些查找,然后更多的插入或删除,然后更多的查找等。这个事件序列的关键特
征是插入、删除和查找都是混合在一起的。一般来说,没有办法预测对树的下一个操作是什么。
在很多应用中,使用数据结构并没有那么混乱。它们对数据结构的使用可以总结为这样的三个截然不同的阶
段:

  1. 建立。通过插入很多元素建立一个新的数据结构。在这个阶段,几乎所有的操作都是插入和删除。几
    乎没有或根本没有查找。
  2. 查找。在数据结构中查找指定的信息片。在这个阶段,几乎所有的操作都是查找。几乎没有或根本没
    有插入和删除。
  3. 重组。修改数据结构的内容,也许通过删除所有现有数据和在原地插入新数据。从动作上说,这个阶
    段等价于阶段1。一旦这个阶段完成,应用程序返回阶段2。
    对于这么使用它们的数据结构的应用来说,一个vector可能比一个关联容器能提供更高的性能(时间和空间
    上都是)。但不是任意的vector都会,只有有序vector。因为只有有序容器才能正确地使用查找算法——
    binary_search、lower_bound、equal_range等

考虑一个Widget的关联容器和一个有序vector。如果我们选择一个关联容器,我们几乎确定了要使
用平衡二叉树。这样的树是由树节点组成,每个都不仅容纳了一个Widget,而且保存了一个该节点到左孩子
的指针,一个到它右孩子的指针,和(典型的)一个到它父节点的指针。这意味着在关联容器中用于存储一
个Widget的空间开销至少会是三个指针。
与之相对的是,当在vector中存储Widget并没有开销:我们简单地存储一个Widget。当然,vector本身有开
销,在vector结尾也可能有空的(保留)空间(参见条款14),但是每个vector开销是可以忽略的(通常是三
个机器字,比如,三个指针或两个指针和一个int),而且如果必要的话,末尾空的空间可以通过“交换技
巧”去掉(看见条款17)。即使这个附加的空间没有去掉,也并不影响下面的分析,因为当查找时不会引用
那段内存

引用局部性,这些节点会分散在所有你的内存空间。那会导
致更多的页面错误。即使使用了自定义群集内存管理器,关联容器也会导致很多页面错误,因为,不像连续
内存容器,比如vector,基于节点的容器更难保证在容器的遍历顺序中一个挨着一个的元素在物理内存上也
是一个挨着一个。

概要:在有序vector中存储数据很有可能比在标准关联容器中保存相同的数据消耗更少的内存;当页面错误
值得重视的时候,在有序vector中通过二分法查找可能比在一个标准关联容器中查找更快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUXfHUMq-1585901574472)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896705214.png)]

条款24:当关乎效率时应该在map::operator[]和map-insert之间仔细选择

map的operator[]函数是个奇怪的东西。它与vector、deque和string的operator[]函数无关,也和内建的数组
operator[]无关。相反,map::operator[]被设计为简化“添加或更新”功能。即,给定

map<K, V> m;
这个表达式

m[k] = v;
检查键k是否已经在map里。如果不,就添加上,以v作为它的对应值。如果k已经在map里,它的关联值被更
新成v。
这项工作的原理是operator[]返回一个与k关联的值对象的引用。然后v赋值给所引用(从operator[]返回的)的
对象。当要更新一个已存在的键的关联值时很直接,因为已经有operator[]可以用来返回引用的值对象。但是
如果k还不在map里,operator[]就没有可以引用的值对象。那样的话,它使用值类型的默认构造函数从头开始
建立一个,然后operator[]返回这个新建立对象的引用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SkYzeGaI-1585901574473)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585896871588.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gyr0bkUf-1585901574474)(C:\Users\w00448203\Documents\MarkDownDoc\1585896953033.png)]

也就是当关乎效率时应该在
map::operator[]和map-insert之间仔细选择。如果你要更新已存在的map元素,operator[]更好,但如果你要增
加一个新元素,insert则有优势。

条款25:熟悉非标准散列容器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NGZ8qJQy-1585901574475)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897009904.png)]

迭代器

条款26:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NTwdXyMf-1585901574477)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897058034.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J96enOQu-1585901574478)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897082539.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-msSnugGb-1585901574479)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897096539.png)]

当在iterator和const_iterator之间作选择的时候,你有更充分的理由选择iterator,即使const_iterator同样可行而
且即使你并不需要调用容器类的任何成员函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9c7esF7o-1585901574479)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897436212.png)]

条款27:用distance和advance把const_iterator转化成iterator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4xNbmeVq-1585901574480)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897469476.png)]

typedef。在这种实现的情况下,用const_cast把const_iterator映射成iterator当然可以编译而且没有问题,因为
const_iterator与iterator之间的const_cast映射被最终解释成const T到T的映射。但是,即使是在这种实现中,
reverse_iterator和const_reverse_iterator也是真正的类,所以你仍然不能直接用const_cast把const_reverse_iterator映
射成reverse_iterator。

这种方法看上去非常简单,直截了当,也很让人吃惊吧。要得到与const_iterator指向同一位置的iterator,首先
将iterator指向容器的起始位置,然后把它向前移到和const_iterator距离容器起始位置的偏移量一样的位置即
可!这个任务得到了两个函数模板advance和distance的帮助,它们都在中声明。distance返回两个指
向同一个容器的iterator之间的距离;advance则用于将一个iterator移动指定的距离。如

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5p2mtn3t-1585901574480)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897499860.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cPeSCrKa-1585901574481)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897529352.png)]

条款28:了解如何通过reverse_iterator的base得到iterator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8i2bPTH1-1585901574481)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897567655.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3rlByFG-1585901574482)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897580686.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q1hCNe7M-1585901574482)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897609181.png)]

条款29:需要一个一个字符输入时考虑使用istreambuf_iterator

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hI1a8jt8-1585901574482)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897661947.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKdCP2kh-1585901574482)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897670893.png)]

算法

条款30:确保目标区间足够大

条款31:了解你的排序选择

条款32:如果你真的想删除东西的话就在类似remove的算法后接上erase

因为remove是STL中最糊涂的算法。误解remove很容易,

这是remove的声明:
template<class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last,
const T& value);
就像所有算法,remove接收指定它操作的元素区间的一对迭代器。它不接收一个容器,所以remove不知道它
作用于哪个容器。此外,remove也不可能发现容器,因为没有办法从一个迭代器获取对应于它的容器。

想想怎么从容器中除去一个元素。唯一的方法是调用那个容器的一个成员函数,几乎都是erase的某个形式,
(list有几个除去元素的成员函数不叫erase,但它们仍然是成员函数。)因为唯一从容器中除去一个元素的方
法是在那个容器上调用一个成员函数,而且因为remove无法知道它正在操作的容器,所以remove不可能从一
个容器中除去元素。这解释了另一个令人沮丧的观点——从一个容器中remove元素不会改变容器中元素的个
数: 这解释了另一个令人沮丧的观点——从一个容器中remove元素不会改变容器中元素的个
数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q53r14Bz-1585901574483)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897927668.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n4GRjBt3-1585901574484)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897958037.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pzucdAqH-1585901574485)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897981585.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUDDFau0-1585901574486)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585897993652.png)]

你可以想象remove完成了一种压缩,被删除的值表演了在压缩中被填充的洞的角色。对于我们的vector v,它
按照下面的表演:

  1. remove检测v[0],发现它的值不是要被删除的,然后移动到v[1]。同样的情况发生在v[1]和v[2]。
  2. 发现v[3]应该被删除,所以它记录下v[3]的值应该被覆盖,然后它移动到v[4]。这类似记录v[3]是一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-msref7Ck-1585901574486)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898059243.png)]

道remove不从容器中除去任何元素因为它做不到就够了。只有容器成员函数可以除去容器元素,而那是本条
款的整个要点:如果你真的要删除东西的话,你应该在remove后面接上erase。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bp8sOu6u-1585901574488)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898080401.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZTTAyAt-1585901574489)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898091700.png)]

条款33:提防在指针的容器上使用类似remove的算法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nWOBBlc-1585901574490)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898144961.png)]

资源泄漏的理由现在很明朗了。指向Widget B和C的“删除的”指针被vector中后面的“不删除的”指针覆
盖。没有什么指向两个未通过检验的Widget,它们也没有被删除,它们的内存和其他资源泄漏了。
一旦remove_if和erase返回后,情况看起来像这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QBB6A4Nb-1585901574490)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898165284.png)]

条款34:注意哪个算法需要有序区间

不是所有算法可以用于任意区间。比如,remove(参见条款32和33)需要前向迭代器和可以通过这些迭代器
赋值的能力。所以,它不能应用于由输入迭代器划分的区间, 很多排序算法(参见条款31)需要随机访问迭代器,所以不可能
在一个list的元素上调用这些算法。

既可以和有序又可以和无序区间合作的算法很少,但当操作有序区间的时候它们最有用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yuzT6b0a-1585901574491)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898284992.png)]

搜索算法binary_search、lower_bound、upper_bound和equal_range(参见条款45)需要有序区间,因为它们使 用二分法查找来搜索值。像C库中的bsearch,这些算法保证了对数时间的查找,但作为交换的是,你必须给
它们已经排过序的值。
实际上,这些算法保证对数时间查找不是很正确。仅当传给它们的是随机访问迭代器时它们才能保证有那样
的性能。如果给它们威力比较小的迭代器(比如双向迭代器),它们仍然进行对数次比较,但运行是线性时
间的。那是因为,缺乏进行“迭代器算术(arithmetic)”的能力。它们在搜索的区间中需要花费线性时间来
从一个地方移动到另一个地方。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hCeI5KjP-1585901574492)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585898321267.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nxmxXnQu-1585901574492)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900036117.png)]

条款35:通过mismatch或lexicographical比较实现简单的忽略大小写字符串比较

条款36:了解copy_if的正确实现

条款37:用accumulate或for_each来统计区间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IG5NcB90-1585901574493)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900100164.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4hvG86Hu-1585901574498)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900153511.png)]

就个人来说,我更喜欢用accumulate来统计,因为我认为它最清楚地表达了正在做什么,但是for_each也可以,而且不像accumulate,副作用的问题并不跟随for_each。两个算法都能用来统计区间。使用最适合你的那个

仿函数、仿函数类、函数等

在你看到的STL中的每个地方,你都可以看见仿函数和仿函数类。包括你的源代码中。如果不知道怎
么写行为良好的仿函数就不可能有效地使用STL。

条款38:把仿函数类设计为用于值传递

这是C和C++标准库都遵循的一般准则,也就是,函数指针是值
传递。
STL函数对象在函数指针之后成型,所以STL中的习惯是当传给函数和从函数返回时函数对象也是值传递的
(也就是拷贝)。最好的证据是标准的for_each声明,这个算法通过值传递获取和返回函数对象:

假设函数对象总是值传递。实际上,这事实上总是真的。
因为函数对象以值传递和返回,你的任务就是确保当那么传递(也就是拷贝)时你的函数对象行为良好。这
暗示了两个东西。第一,你的函数对象应该很小。否则它们的拷贝会很昂贵。第二,你的函数对象必须单态
(也就是,非多态)——它们不能用虚函数。

条款39:用纯函数做判断式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sI77uYRv-1585901574503)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900305357.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cxA8HUDO-1585901574506)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900318322.png)]

条款40:使仿函数类可适配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SljA0wdI-1585901574508)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900359412.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gM3FJrOR-1585901574509)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900369715.png)]

在这里,传给binary_function的类型和operator()所带的类型一样。用于带有或返回指针的仿函数的一般规则是传给unary_function或binary_function的类型是operator()带有或返回的类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ftqCVJjl-1585901574509)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900414960.png)]

STL暗中假设每个
仿函数类只有一个operator()函数,而且这个函数的参数和返回类型要被传给unary_function或binary_function

条款41:了解使用ptr_fun、mem_fun和mem_fun_ref的原因

mem_fun和mem_fun_ref完成这个的方式很简单,虽然如果你看一下这些函数之一的声明会稍微清楚些。它们是真的函数模板,而且存在mem_fun和mem_fun_ref模板的几个变体,

总的来说,mem_fun适配语法#3——也就是当和Widget*指针配合时Widget::test要求的——到语法1,也就是
for_each用的。因此也不奇怪像mem_fun_t这样的类被称为函数对象适配器。知道这个不应该使你惊讶,完全
类似上述的,mem_fun_ref函数适配语法#2到语法#1,并产生mem_fun_ref_t类型的适配器对象

for_each没有使用ptr_fun增加的typedef,所以当把test传给for_each时不必使用
ptr_fun。

如果你关于什么时候使用ptr_fun什么时候不使用而感到困惑,那就考虑每当你传递一个函数给STL组件时都
使用它。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pTnFo8H9-1585901574510)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900574492.png)]

条款42:确定less表示operator<

operator<不仅是实现less的默认方式,它还是程序员希望less做的。让less做除operator<以外的事情是对程序员
预期的无故破坏。它与所被称为“最小惊讶的原则”相反。

multiset<Widget, MaxSpeedCompare> widgets;
这条代码确切地说出了它的意思。它建立了一个Widget的multiset,

这个表示widgets是一个以默认方式排序的Widget的multiset。在技术上,那表示它使用了less,但是实
际上每人都要假设那真的意味着它是按operator<来排序。
不要通过把less的定义当儿戏来误导那些程序员。如果你使用less(明确或者隐含),保证它表示operator<。
如果你想要使用一些其他标准排序对象,建立一个特殊的不叫做less的仿函数类。它真的很简单。

使用STL编程

总结由容器、迭代器、算法和函数对象组成的STL是个惯例,

条款43:尽量用算法调用代替手写循环

所以,算法内部是一个循环。此外,STL算法的广泛涉及面意味着很多你本来要用循环来实现的任务,现在
可以改用算法来实现了。比如,如果你有一个支持重画的Widget类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1DpDXeen-1585901574511)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900653796.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49sEiUrw-1585901574513)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900668349.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5M3PtfAN-1585901574517)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900678821.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9FbIF5dM-1585901574518)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900687692.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kntgcEcZ-1585901574523)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900705134.png)]

“bind2nd(plus(), 41)”可能会花上一些时间才能看明白(尤其是如果不常用STL的bind族的
话),但是与迭代器相关的唯一烦扰就是指出源区间的起始点和结束点(而这从不会成为问题),并确保在
目的区间的起始点上使用inserter(参见条款30)。实际上,为源区间和目的区间指出正确的初始迭代器通常
都很容易,至少比确保循环体没有于无意中将需要持续使用的迭代器变得无效要容易得多。
难以正确实现循环的情况太多了,这个例子只是比较有代表性。因为在使用迭代器前,必须时刻关注它们是
否被不正确地操纵或变得无效。

算法为什么可以比手写的循环更高效,也描述了为什么循环将艰难地穿行于与迭代器相关的荆
棘丛中,而算法正避免了这一点。

有理由认为专业的C++程序员知道(或应该去看一下)每
个算法都完成了什么。因此,当程序员调用transform时,他们认为对区间内的每个元素都施加了某个函数,
而结果将被写到另外一个地方。当程序员调用replace_if时,他(她)知道区间内满足判定条件的对象都将被
修改。当调用partition时,她(他)明白区间中所有满足判定条件的对象将被聚集在一起(参见条款31)。
STL算法的名字传达了大量的语义信息,这使得它们比随机的循环清晰多了

明摆着,算法的名字暗示了其功能。“for”、“while”和“do”却做不到这一点。

没道理用循环来实现出已存在的STL算法的等价版本。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sfZNvmrK-1585901574526)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900764341.png)]

条款44:尽量用成员函数代替同名的算法

有些容器拥有和STL算法同名的成员函数。关联容器提供了count、find、lower_bound、upper_bound和
equal_range,而list提供了remove、remove_if、unique、sort、merge和reverse。大多数情况下,你应该用成员函
数代替算法。这样做有两个理由。首先,成员函数更快。其次,比起算法来,它们与容器结合得更好(尤其
是关联容器)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eq07UVJ8-1585901574527)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900789189.png)]

效率不是find成员函数和find算法间的唯一差别。正如条款19所解释的,STL算法判断两个对象是否相同的方
法是检查的是它们是否相等,而关联容器是用等价来测试它们的“同一性”。 因此,find算法搜索727用的是
相等,而find成员函数用的是等价。相等和等价间的区别可能造成成功搜索和不成功搜索的区别。比如说,
条款19演示了用find算法在关联容器搜索失败而用find成员函数却搜索成功的情况!因此,如果使用关联容器
的话,你应该尽量使用成员函数形式的find、count、lower_bound等等,而不是同名的算法,因为这些成员函
数版本提供了和其它成员函数一致的行为。由于相等和等价间的差别,算法不能提供这样的一致行为。

对于标准的关联容器,选择成员函数而不是同名的算法有几个好处。首先,你得到的是对数时间而不是线性
时间的性能。其次,你判断两个元素“相同”使用的是等价,这是关联容器的默认定义。第三,当操纵map
和multimap时,你可以自动地只处理key值而不是(key, value)对。这三点给了优先使用成员函数完美的铁甲。

牢牢记住这一点很重要:list成员函数的行为和它们的算法兄弟的行为经常不相同。正如条款32所解释的,如
果你真的想从容器中清除对象的话,调用remove、remove_if和unique算法后,必须紧接着调用erase函数;但
list的remove、remove_if和unique成员函数真的去掉了元素,后面不需要接着调用erase。
在sort算法和list的sort成员函数间的一个重要区别是前者不能用于list。作为单纯的双向迭代器,list的迭代器不
能传给sort算法。merge算法和list的merge成员函数之间也同样存在巨大差异。这个算法被限制为不能修改源
范围,但list::merge总是修改它的宿主list。
所以,你明白了吧。当面临着STL算法和同名的容器成员函数间进行选择时,你应该尽量使用成员函数。几
乎可以肯定它更高效,而且它看起来也和容器的惯常行为集成得更好。

条款45:注意count、find、binary_search、lower_bound、upper_bound和equal_range的区别

有序区间。如果是,你就可以通过binary_search、
lower_bound、upper_bound和equal_range来加速(通常是对数时间——参见条款34)搜索。如果迭代器并没有
划分一个有序区间,你就只能用线性时间的算法count、count_if、find和find_if。

count回答的问题是:“是否存在这个值,如果有,那么存在几份拷贝?”而find回答的问题
是:“是否存在,如果有,那么它在哪儿?”

这里示范了一种惯用法:把count用来作为是否存在的检查。count返回零或者一个正数,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l8IYEccg-1585901574529)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900869143.png)]

find算法都用相等来搜索,而binary_search、lower_bound、upper_bound和equal_range则用等价

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fn9ISnGj-1585901574536)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900888737.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E3sCzSdH-1585901574541)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900908907.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aCxlzF0r-1585901574544)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900935564.png)]

第二个要注意的是equal_range返回的东西是两个迭代器,对它们作distance就等于区间中对象的数目,也就是,等价于要寻找的值的对象。结果,equal_range不光完成了搜索有序区间的任务,而且完成了计数。比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eq3kQ3ar-1585901574547)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900971861.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbtiNcH4-1585901574549)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585900983935.png)]

条款46:考虑使用函数对象代替函数作算法的参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GRWSSJg2-1585901574553)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585901004329.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yzdog6wc-1585901574555)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585901015308.png)]

把函数对象作为算法的参数所带来的不仅是巨大的效率提升。在让你的代码可以编译方面,它们也更稳健。

条款47:避免产生只写代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-meiRk52S-1585901574556)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585901279613.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y4EqLfXo-1585901574556)(C:\Users\w00448203\AppData\Roaming\Typora\typora-user-images\1585901292764.png)]

e就等于区间中对象的数目,也就是,等价于要寻找的值的对象。结果,equal_range不光完成了搜索有序区间的任务,而且完成了计数。比

[外链图片转存中…(img-Eq3kQ3ar-1585901574547)]

[外链图片转存中…(img-jbtiNcH4-1585901574549)]

条款46:考虑使用函数对象代替函数作算法的参数

[外链图片转存中…(img-GRWSSJg2-1585901574553)]

[外链图片转存中…(img-yzdog6wc-1585901574555)]

把函数对象作为算法的参数所带来的不仅是巨大的效率提升。在让你的代码可以编译方面,它们也更稳健。

条款47:避免产生只写代码

[外链图片转存中…(img-meiRk52S-1585901574556)]

[外链图片转存中…(img-y4EqLfXo-1585901574556)]

条款48:总是#include适当的头文件

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Effective STL 的相关文章

  • 提升企业网络安全的重要性:EventLog Analyzer的角色

    在今天的数字时代 企业对网络安全的需求愈发迫切 随着互联网的不断发展和企业信息的数字化 网络攻击的威胁也不断增加 为了保护企业数据和系统的完整性 网络安全已经成为每个企业都必须认真对待的重要问题 在这个背景下 我们不得不提到一种强大的工具
  • SSM+mysql课程题库管理系统-计算机毕业设计源码18655

    摘 要 随着科学技术的飞速发展 各行各业都在努力与现代先进技术接轨 通过科技手段提高自身的优势 对于课程题库管理系统当然也不能排除在外 随着网络技术的不断成熟 带动了课程题库管理系统 它彻底改变了过去传统的管理方式 不仅使服务管理难度变低了
  • ENVI_IDL: 基础语法详解

    01 题目 02 代码说明 题目本身很简单 但是我自己加了一些东西进去增加难度 主要包括print函数的封装 格式化字符串 但是不影响代码的阅读 注 对于没有语言基础的人而言相对阅读困难 但是由于IDL是解释型语言 类似于Python 所以
  • 【PyTorch】如何取得预训练模型的标签label列表(以 Alexnet 在 ImageNet 上的预训练模型为例)

    PyTorch 预训练模型 PyTorch 提供过了大量的预训练模型可以直接拿来使用 或者进行增量训练和微调 拿 Alexnet 的预训练模型为例 import torch import torchvision model torchvis
  • Ubuntu系统下 .7z 文件压缩解压命令

    安装软件 sudo apt install p7zip full 解压文件 解压命令 7z x filename 7z r o test 参数说明 7z 解压缩文件命令 x 表示解压缩 r 表示递归解压缩所有的子文件夹 o 指定解压到的那个
  • JProfile 分析OOM hprof文件

    JProfile 分析OOM OutOfMemoryError 1 JVM组成 首先要明白JVM组成 方法区 非堆 Method Area No Heap Java栈 虚拟机栈 VM Stack Java Stack 本地方法栈 Nativ
  • 解决浏览器”您的连接不是私密链接“的问题!最详细!!!

    Google的Chorom浏览器打开baidu主页 显示 您的连接不是私密连接 攻击者可能会试图从 x x x x 窃取您的信息 例如 密码 通讯内容或信用卡信息 了解详情 NET ERR CERT INVALID 网上找了很多人的解决办法
  • LeetCode 465. Optimal Account Balancing

    原题网址 https leetcode com problems optimal account balancing A group of friends went on holiday and sometimes lent each ot
  • linux ftp查看用户目录权限,linux 指定ftp用户 特定目录及权限

    Linux添加FTP用户并设置权限 在linux中添加ftp用户 并设置相应的权限 操作步骤如下 1 环境 ftp为vsftp 被限制用户名为test 被限制路径为 home test 2 建用户 在root用户下 useradd d ho
  • MyBatis-Plus——代码自动生成器

    哈喽 大家好 我是 一位上进心十足的 Java领域博主 的写作风格 喜欢用 通俗易懂 的文笔去讲解每一个知识点 而不喜欢用 高大上 的官方陈述 博客的领域是 面向后端技术 的学习 未来会持续更新更多的 后端技术 以及 学习心得 如果有对 后
  • Cesium中文教程-Cesium Workshop(一)

    欢迎来到Cesium社区 非常高兴能加入我们 为了帮助您开发自己的web地图应用程序 本教程将从头到尾介绍如何开发一款简单但有广泛影响的Cesium应用程序 本教程将接触到许多CesiumJS API重要的方面 但这并不意味着包括所有 Ce
  • openLDAP安装卸载与重装

    安装卸载 安装与卸载点击跳转 openLDAP与phpldapadmin安装点击跳转 重装问题 点击跳转
  • 基于SpringBoot工程开发Docker化微服务

    目录 1 微服务容器化治理的优缺点 1 1 微服务容器化的优点 1 2 微服务容器化的缺点 2 微服务的两种模式 2 1 Microservice SDK 2 2 ServiceMesh 3 微服务容器化治理的推荐模式 4 Windows下
  • 湖南省副省长秦国文一行调研考察亚信科技

    9月5日 湖南省人民政府党组成员 副省长秦国文一行到亚信科技调研考察 亚信科技高级副总裁陈武主持接待 图 双方合影 在亚信科技创新展示中心 秦国文了解了亚信科技在5G 算力网络 人工智能 大数据等前沿领域的创新探索 在数字化运营 智慧城市
  • 使用java API操作hdfs--读取hdfs文件并打印

    在myclass之中创建类文件 这个myclass目录是自己创建的 编译的时候会报如下的错误 很明显就是没有导入包的结果 见这个API网站 则可以找到响应的包 当然还有java的api文档 http hadoop apache org do
  • Java程序Png图片保持透明度处理

    核心代码 import javax imageio ImageIO import java awt import java awt image BufferedImage import java io File import java io
  • Springboot调整接口响应返回时长(解决响应超时问题)

    Springboot调整接口 会话响应返回时长 解决响应超时问题 配置Http会话超时 可以通过两种方式为Spring Boot应用程序配置HTTP会话超时 application properties中配置会话超时 最简单的方法是在你的a
  • 在互联网上,没有人知道你是一条狗?

    1993 年 纽约客 The New Yorker 杂志刊登一则由彼得 施泰纳 Peter Steiner 创作的漫画 标题是 On the Internet nobody knows you re a dog 这则漫画中有两只狗 一只黑狗
  • 【C语言】通讯录实现以及信息保存至文件。

    实现一个通讯录 通讯录用来存放1000个人的信息 每个人的信息包括 姓名 性别 年龄 电话 住址 提供方法 1 添加联系人信息 2 删除指定联系人信息 3 查找指定联系人的信息 4 修改指定联系人信息 5 显示所有联系人信息 6 清空所有联

随机推荐

  • c++内存分区模型

    程序在运行的过程中是会被加载到内存中的 一个程序可能会执行可能会存在不同的功能块 所以不同区域存放的数据 赋予不同的生命周期 给我们更大的灵活编程 C 的程序会在内存中分为四大块 代码区 存放函数体的二进制代码 由操作系统进行管理的 全局区
  • vue在created调用点击方法_vue.js中created方法的使用详解

    这次给大家带来vue js中created方法的使用详解 使用vue js中created方法的注意事项有哪些 下面就是实战案例 一起来看一下 这是它的一个生命周期钩子函数 就是一个vue实例被生成后调用这个函数 一个vue实例被生成后还要
  • 什么是公有IP地址?什么是私有IP地址?及各自范围介绍

    什么是公有IP地址 公网IP 组建一个企业级网络 需要去向 电信运营商ISP 申请一个接入Internet的宽带 同时ISP还会给我们分配一个或多个IP地址 这些IP地址可以供我们企业内部上网 这些ISP分配给我们的IP 就是公有IP 公有
  • 柯里化的两种实现方式(定参和不定参)

    1 函数柯里化简介 函数柯里化是指把接收多个参数的函数转换为接受单一参数的函数 并返回接收剩下参数的新函数的技术 通俗点说 就是将多元函数转化为多个单元函数的连续定义 这里的元代指参数 也就说函数柯里化可以把f a b c 这样的多参的函数
  • Freebsd系统ssh登陆配置

    FreeBSD SSH配置详解 默认情况下freebsd下的ssh服务是未被开启的 需要 首先vi编辑 etc inetd conf 去掉ssh前的 保存退出 开启 ssh服务 修改freebsd可以用sshd权限用户登录ssh 但不能用r
  • JPA学习笔记 - 关联关系

    OneToMany 指定 1对多 的映射关系 可通过fetch的属性设置加载方式 JoinColmn 指定外键的列名 外键存在于 多 的一方表中 单向 n 1 先保存n的一端时 会多出update语句 因为插入n端时并未知道外键的值 插入1
  • java8 新特性stream流学习

    简介 java 8 API添加了一个新的抽象称为流Stream 可以让你以一种声明的方式处理数据 Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象 Stream API可以
  • 离散数学-二元关系

    目录 序偶与有序n元组 集合的笛卡尔积 关系的基本概念 关系的表示方法 特殊关系 关系的性质 自反性 反自反性 对称性 反对称性 传递性 关系的复合运算 1 基本概念 2 计算方法 2 1 有向图法 2 2 枚举法 2 3 谓词公式法 3
  • 微信小程序实现文字随机颜色

    1 实现效果 2 实现思路 从颜色列表中随机取一个颜色 赋值给数组的每一项 Math floor Math random colorArr length 3 实现代码
  • python爬虫需要哪些基础知识-【PYTHON】【爬虫】关于python爬虫的一些基础知识

    基础知识 HTTP协议 我们浏览网页的浏览器和手机应用客户端与服务器通信几乎都是基于HTTP协议 而爬虫可以看作是一个另类的客户端 它把自己伪装成浏览器或者手机应用客户端 按照自己的逻辑贪婪的向服务器索取数据 如何向服务器索取数据 所以了解
  • android开启安装权限管理,Android6.0权限——安装时默认开启app全部权限

    1 默认开启app全部权限 Android6 0之后推出动态申请权限 所有敏感权限默认都是没有开启的状态 这两天偶然间看到其他app安装后所有权限 包括敏感权限 默认都是开启的状态 6 0之后敏感权限都需要申请的 怎么可能跨过用户的 好奇心
  • 5种常用格式的数据输出,手把手教你用Pandas实现

    导读 任何原始格式的数据载入DataFrame后 都可以使用类似DataFrame to csv 的方法输出到相应格式的文件或者目标系统里 本文将介绍一些常用的数据输出目标格式 01 CSV DataFrame to csv方法可以将Dat
  • webcomponents安装了没有用_Web Components基本概念及实例教程

    谷歌公司由于掌握了 Chrome 浏览器 一直在推动浏览器的原生组件 即 Web Components API 相比第三方框架 原生组件简单直接 符合直觉 不用加载任何外部模块 代码量小 目前 它还在不断发展 但已经可用于生产环境 基本概念
  • 如何使用 Javadoc 工具生成文档

    Javadoc 是一个由 Java 语言编写的工具 用于从 Java 代码中提取注释并生成 HTML 格式的文档 以下是使用 Javadoc 工具生成文档的一般步骤 编写代码并添加注释 在你的 Java 代码中添加注释是生成文档的关键 Ja
  • pycharm连接ssh debug卡住 解决方案

    修改dataloder中的worker 修改pycharm setting
  • 2021经典优秀计算机单片机毕业设计题目

    可追溯农产品电商管理系统的设计与实现 农产品用户商城系统设计与实现 基于OpenGL的全局光照算法的设计与实现 分布式存储系统分析与设计 基于机器学习的数据库融合技术研究 基于知识图谱的对话系统设计与实现 具有日志的虚拟WEB攻防系统设计与
  • 蓝桥杯省赛模拟题 信号覆盖

    题目大意 小蓝负责一块区域的信号塔安装 整块区域是一个长方形区域 建立坐标轴后 西南角坐标为 0 0 0 0 0 0 东南角坐标为
  • 计算机恢复语言文件格式,txt文件乱码怎么恢复正常

    txt是最常见的一种文件格式 几乎所有的文本编辑器都可以打开和编辑TXT文件 不过有网友在打开该文件时却遇到了乱码的情况 这是怎么回事呢 我们该如何操作才能使之恢复正常呢 用户可能不是很了解 所以今天本文为大家分享的就是电脑打开txt文档乱
  • ChatGPT + Stable Diffusion + 百度AI + MoviePy 实现文字生成视频,小说转视频,自媒体神器!(二)

    ChatGPT Stable Diffusion 百度AI MoviePy 实现文字生成视频 小说转视频 自媒体神器 二 前言 最近大模型频出 但是对于我们普通人来说 如何使用这些AI工具来辅助我们的工作呢 或者参与进入我们的生活 就着现在
  • Effective STL

    外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img qcpwxQhi 1585901574462 C Users w00448203 AppData Roaming Typora typora user images