http://blog.csdn.net/amin2001/article/details/8063

STL容器在被添加时(通过insert、push_front、push_back等)自动扩展它们自己来容纳新对象。这工作的很好,有些程序员因为这个信仰而被麻痹,认为他们不必担心要为容器中的对象腾出空间,因为容器自己可以照顾好这些。如果是那样就好了!当程序员想向容器中插入对象但并没有告诉STL他们所想的时,问题出现了。这是一个常见的可以自我表现的方法:

int transmogrify(int x);     // 这个函数从x// 产生一些新值
vector<int> values;
...       // 把数据放入values
vector<int> results;     // 把transmogrify应用于
transform(values.begin(), values.end(),   // values中的每个对象results.end(),    // 把这个返回的valuestransmogrify);    // 附加到results// 这段代码有bug!

在本例中,transform被告知它的目的区间是从results.end()开始的,所以那就是开始写在values的每个元素上调用transmogrify的结果的地方。就像所有使用目标区间的算法,transform通过对目标区间的元素赋值的方法写入结果,transform会把transmogrify应用于values[0]并把结果赋给*results.end()。然后它会把transmogrify应用于value[1]并把结果赋给*(results.end()+1)。那只能带来灾难,因为在*results.end()没有对象,*(results.end()+1)也没有!调用transform是错误的,因为它会给不存在的对象赋值。(条款50解释了STL的一个调试实现怎么在运行期检测这个问题。)犯了这种错误的程序员几乎总是以为他们调用算法的结果能插入目标容器。如果那是你想要发生的,你就必须说出来。STL是一个库,不是一个精神。在本例中,说“请把transform的结果放入叫做results容器的结尾”的方式是调用back_inserter来产生指定目标区间起点的迭代器:

vector<int> results;     // 把transmogrify应用于
transform(values.begin(), values.end(),   // values中的每个对象,back_inserter(results),  // 在results的结尾transmogrify);   // 插入返回的values

在内部,back_inserter返回的迭代器会调用push_back,所以你可以在任何提供push_back的容器上使用back_inserter(也就是任何标准序列容器:vector、string、deque和list)。如果你想让一个算法在容器的前端插入东西,你可以使用front_inserter。在内部,front_inserter利用了push_front,所以front_insert只和提供那个成员函数的容器配合(也就是deque和list):

...       // 同上
list<int> results;      // results现在是list
transform(values.begin(), values.end(),   // 在results前端front_inserter(results),  // 以反序transmogrify);   // 插入transform的结果

因为front_inserter用push_front把每个对象添加到results,results中的对象顺序会和values中对应的对象顺序相反。这也是为什么front_inserter没有back_inserter那么常用的原因之一。另一个原因是vector不提供push_front,所以front_inserter不能用于vector。

如果你要transform把输出结果放在results前端,但你也要输出和values中对应的对象顺序相同,只要以相反的顺序迭代values:

list<int> results;      // 同上
transform(values.rbegin(), values.rend(),   // 在results前端front_inserter(results),  // 插入transform的结果transmogrify);   // 保持相对的对象顺序

front_inserter让你强制算法在容器前端插入它们的结果,back_inserter让你告诉它们把结果放在容器后端,有点惊人的是inserter允许你强制算法把它们的结果插入容器中的任意位置:

vector<int> values;     // 同上
...
vector<int> results;     // 同上,除了现在
...       // 在调用transform前// results已经有一些数据
transform(values.begin(), values.end(),   // 把transmogrify的inserter(results, results.begin() + results.size()/2), // 结果插入transmogrify);     // results的中间

不管你是否使用了back_inserter、front_inserter或inserter,每次对目的区间的插入只完成一个对象。条款5解释了对于连续内存容器(vector、string和deque)来说这可能很昂贵,但条款5的建议解决方法(使用区间成员函数)不能应用于使用算法来完成插入的情况。在本例中,transform会对目的区间每次写入一个值,你无法改变。

当你要插入的容器是vector或string时,你可以通过按照条款14的建议最小化这个代价,预先调用reserve。你仍然要承受每次发生插入时移动元素的开销,但至少你避免了重新分配容器的内在内存:

vector<int> values;     // 同上
vector<int> results;
...
results.reserve(results.size() + values.size());  // 确定results至少// 还能装得下// values.size()个元素
transform(values.begin(), values.end(),   // 同上,inserter(results, results.begin() + results.size() / 2),// 但resultstransmogrify);     // 没有任何重新分配操作

当使用reserve来提高一连串插入的效率时,总是应该记住reserve只增加容器的容量:容器的大小仍然没有改变。即使调用完reserve,当你想要让容器把新元素加入到vector或string时,你也必须对算法使用插入迭代器(比如,从back_inserter、front_inserter或inserter返回的迭代器之一)。

要把这些完全弄清楚,这里有一个提高本条款开始时的那个例子的效率的错误方法(就是我们把transmogrify作用于values里的数据的结果附加到results的那个例子):

vector<int> values;    // 同上
vector<int> results;
...
results.reserve(results.size() + values.size()); // 同上
transform(values.begin(), values.end(),  // 写入transmogrify的结果results.end(),   // 到未初始化的内存transmogrify);   // 行为未定义!

在这段代码中,transform愉快地试图对results尾部的原始的、未初始化的内存赋值。通常,这会造成运行期错误,因为赋值只在两个对象之间操作时有意义,而不是在一个对象和一块原始的比特之间。即使这段代码碰巧作了你想要它做的事情,results也不会知道transform在它的未使用容量上“创造”的新“对象”。直到results知道之前,它的大小在调用transform后仍然和原来一样。同样的,它的end迭代器仍和调用transform前指向同样的位置。结论呢?使用reserve而没有用插入迭代器会在算法内部导致未定义行为,也会弄乱容器。

正确地写这个例子的代码的方法是使用reserve和插入迭代器:

vector<int> values;    // 同上
vector<int> results;
results.reserve(results.size() + values.size()); // 同上
transform(values.begin(), values.end(),  // 把transmogrify的结果back_inserter(results),  // 写入results的结尾,transmogrify);   // 处理时避免了重新分配

到目前为止,我都在假设你让像transform那样的算法把它们的结果作为新元素插入容器。这是通常的期望,但有时候你要覆盖现有容器的元素而不是插入新的。当这种情况时,你不需要插入迭代器,但你仍然需要按照本条款的建议来确保你的目的区间足够大。

比如,假设你让transform覆盖results的元素。如果results至少有和values一样多的元素,那很简单。如果没有,你也必须使用resize来确保它有。

vector<int> values;
vector<int> results;
...
if (results.size() < values.size()){  // 确保results至少results.resize(values.size());  // 和values一样大
}
transform(values.begin(), values.end(),  // 覆盖values.size()个results.begin(),   // results的元素transmogrify);

或者你可以清空results然后用通常的方式使用插入迭代器:

...
results.clear();     // 销毁results中// 的所有元素
results.reserve(values.size());   // 保留足够空间
transform(values.begin(), values.end(),  // 把transform地返回值pack_inserter(results),  // 放入resultstransmogrify);

本条款论证了这个主题的很多变化,但我希望你能牢牢记住本质。无论何时你使用一个要求指定目的区间的算法,确保目的区间已经足够大或者在算法执行时可以增加大小。如果你选择增加大小,就使用插入迭代器,比如ostream_iterators或从back_inserter、front_inserter或inserter返回的迭代器。这是所有你需要记住的东西。

注意:

copy(ve.begin(),ve.end(),back_inserter(v1));是将ve的数据插入到v1的后面

一:函数模板类
    1、一元函数原型
      template<class _A,class _R>
      struct unary_function
      {
            typedef _A argument_type;
            typedef _R result_type;
      };

2、二元函数原型
      template<class Arg1,class Arg2,class Result>
      struct unary_function
      {
            typedef Arg1 first_argument_type;
            typedef Arg2 Second_argument_type;
            typedef Result result_type;
      };

3、系统函数对象
      plus             返回两个数的和:a+b    
      minus            返回两个数的差:a-b
      multiplies       返回两个数的乘积:a*b
      divides          返回两个数的商:a/b
      mudulus          返回两个数的模:a%b
      negate           返回某个数的相反数:-a

equal_to         判断两个数是否相等:a==b
      not_equal_to     判断两个数是否不等:a!=b
      greater          判断第一个数是否大于第二个数:a>b
      less             判断第一个数是否小于第二个数:a<b
      greate_equal     判断第一个数是否大于等于第二个数:a>=b
      less_equal       判断第一个数是否小于等于第二个数:a<=b

logical_and      返回两个数的逻辑与结果:a&&b
      logical_or       返回两个数的逻辑或结果:a||b
      logical_not      返回某个数的逻辑非结果:!a
 
二:通用容器
    1、vector

vector/vector(int nSize)      创建向量容器
      assign                        对Vector中的元素赋值
      at                            返回指定位置的元素
      back                          返回最末一个元素
      begin                         返回第一个元素的迭代器
      capacity                      返回vector所能容纳的元素数量(在不重新分配内存的情况下)
      clear                         清空所有元素
      empty                         判断Vector是否为空(返回true时为空)
      end                           返回最末元素的迭代器(译注:实指向最末元素的下一个位置)
      erase                         删除指定元素
      front                         返回第一个元素
      get_allocator                 返回vector的内存分配器
      insert                        插入元素到Vector中
      max_size                      返回Vector所能容纳元素的最大数量(上限)
      pop_back                      移除最后一个元素
      push_back                     在Vector最后添加一个元素
      rbegin                        返回Vector尾部的逆迭代器
      rend                          返回Vector起始的逆迭代器
      reserve                       设置Vector最小的元素容纳数量
      resize                        改变Vector元素数量的大小
      size                          返回Vector元素数量的大小
      swap                          交换两个Vector

2、list
      assign                        给list赋值
      back                          返回最后一个元素
      begin                         返回指向第一个元素的迭代器
      clear                         删除所有元素
      empty                         如果list是空的则返回true
      end                           返回末尾的迭代器
      erase                         删除一个元素
      front                         返回第一个元素
      get_allocator                 返回list的配置器
      insert                        插入一个元素到list中
      max_size                      返回list能容纳的最大元素数量
      merge                         合并两个list
      pop_back                      删除最后一个元素
      pop_front                     删除第一个元素
      push_back                     在list的末尾添加一个元素
      push_front                    在list的头部添加一个元素
      rbegin                        返回指向第一个元素的逆向迭代器
      remove                        从list删除元素
      remove_if                     按指定条件删除元素
      rend                          指向list末尾的逆向迭代器
      resize                        改变list的大小
      reverse                       把list的元素倒转
      size                          返回list中的元素个数 
      sort                          给list排序
      splice                        合并两个list
      swap                          交换两个list
      unique                        删除list中重复的元素
    3、deque
      push_front                      头部添加一个元素
      push_back                       尾部添加一个元素
      insert                          插入一个元素
      erase                           删除一个元素
      pop_front                       删除最前一个元素
      pop_back                        删除最后一个元素
      clear                           清楚所有元素
      at                              返回指定位置的元素
    4、stack
      stack<class T,class Container = deque/vector/list<T>>   构造栈
      empty                                                 堆栈为空则返回真
      pop                                                   移除栈顶元素
      push                                                  在栈顶增加元素
      size                                                  返回栈中元素数目
      top                                                   返回栈顶元素

5、queue
      queue<class T,class Container = deque/list<T>>          构造队列
      back                                                  返回最后一个元素
      empty                                                 如果队列空则返回真
      front                                                 返回第一个元素
      pop                                                   删除第一个元素
      push                                                  在末尾加入一个元素
      size                                                  返回队列中元素的个数
    6、set
      begin                指向set的头指针
      clear                删除所有元素
      count                返回某键值元素的个数
      empty                返回是否为空
      end                  指向set的尾指针
      erase                删除某位置元素

pair<iterator, iterator>equal_range(const key_type& x)         返回一个迭代器对(指向键不小于x的第一个元素的迭代器,指向键大于x的第一个元素的迭代器)

find                 返回某索引元素指针
      get_allocator        返回构造函数的一个拷贝

pair<iterator,bool>insert(const value_type& x)返回<指向元素x的迭代器,是否插入成功>

lower_bound          返回键值不小于某值的第一个元素的迭代器
      max_size             返回该set可以控制的最大长度
      rbegin               返回反向set的反向头指针
      rend                 返回反响set的反向尾指针
      resize(size_type Sz, T C=T())                                  插入或删除使元素的个数为n,插入的元素为C
    7、map
      map(const Pred& comp=Pred(),const A& al=A())                           构造函数
      pair<const_iterator,const_iterator>equal_range(const Key& key)const:   返回迭代器中键值等于key的迭代指针[fitst,last)
    8、迭代器函数
      back_inserter        返回容器的后插迭代器
      front_inserter       返回容器的前插迭代器

三:非变异算法
   
    1、循环
      for_each               对每个元素执行相同的函数操作
   
    2、查询
      find                   某值第一次出现位置
      find_if                符合某谓词的第一个元素
      find_first_of          子序列某元素第一次出现位置
      adjacent_find          第一次相邻元素相等的位置
      find_end               子序列最后出现位置
      search                 子序列第一次出现位置
      search_n               一个值连续出现n次的位置
    3、计数
      count                  某值出现的此时
      count_if               与某谓词匹配的次数
    4、比较
      equal                  两个序列对应元素都相同为真
      mismatch               两个序列相异的第一个元素

四:变异算法
    1、变换
      transform              将某操作应用于指定范围的元素
    2、填充
      fill                   用给定值填充所有元素
    3、生成
      generate               用一操作的结果填充所有元素
    4、唯一
      unique/unique_copy     删除相邻位置重复的元素
    5、反转
      reverse/reverse_copy   循环移动元素
    6、随机
      random_shuffle         随机移动元素
    7、划分
      partition/stable_paritition 满足谓词的元素都放在前面
五:排序及相关操作

1、排序
      sort                         以很好的平均效率排序
      stable_sort                  稳定排序
      partial_sort                 局部排序
      partial_sort_copy            复制时进行局部排序

2、二分检索
      lower_bound                  大于等于某值第一次出现的迭代器位置
      upper_bound                  大于某值第一次出现位置
      equal_range                  等于某值迭代器范围
      binary_search                是否存在某值

3、归并
      merge                        归并两个迭代器有序序列
      inplace_merge                归并单个迭代器有序序列

4、有序结构上的集合操作
      includes                     一个序列为另一个序列子集为真
      set_union                    构造两集合有序并集
      set_intersection             构造有序交集
      set_difference               构造有序差集
      set_symmetric_difference     构造有序对称差

5、堆操作
      make_heap                    从序列构造堆
      pop_heap                     从堆中弹出元素
      push_heap                    加入元素
      sort_heap                    排序

6、最大最小
      max
      min
      min_element
      max_element

7、词典比较
      lexicographical_compare      两个序列按字典序排序

8、排列生成器
      next_permutation             按字典序的下一个排序
      prev_permutation             按字典序的上一个排序

9、数值算法
      accumulate                   累积求和
      inner_product                内积求和
      partial_sum                  创建新序列,每个元素值代表指定范围内该位置前所有元素之和
      adjacent_difference          相邻元素差集

http://www.crackerban.com/?p=1158

Effective STL 条款30相关推荐

  1. Effective C++条款30:透彻了解inlining的里里外外(Understand the ins and outs of inlining)

    Effective C++条款30:透彻了解inlining的里里外外(Understand the ins and outs of inlining) 条款30:透彻了解inlining的里里外外 ...

  2. Effective C++ 条款30、31

    条款30 透彻了解inlining的里里外外 Inline函数,看起来像函数,动作像函数,比宏好得多,可以调用它们又不需要蒙受函数调用所招致的额外开销.但是,就像世界没有免费的午餐一样,inline的 ...

  3. effective stl 条款15 小心string实现的多样性

    实际上每个string实现都容纳了下面的信息: ● 字符串的大小,也就是它包含的字符的数目. ● 容纳字符串字符的内存容量.(字符串大小和容量之间差别的回顾,参见条款14.) ● 这个字符串的值,也就 ...

  4. 《Effective STL》条款解读

    条款01:慎重选择容器类型 vector.list和deque有着不同的复杂度,vector是默认使用的序列类型.当需要频繁在序列中间做插入和删除操作时,应使用list.当大多数插入和删除操作发生在序 ...

  5. 《Effective STL》学习笔记(第一部分)

    本书从STL应用出发,介绍了在项目中应该怎样正确高效的使用STL.本书共有7个小节50个条款,分别为 (1) 容器:占12个条款,主要介绍了所有容器的共同指导法则 (2) vector和string: ...

  6. effective c++条款44 将与参数无关的代码抽离templates

    effective c++条款44 将与参数无关的代码抽离templates 首先了解这个条款的含义:使用template可能导致代码膨胀,二进制码会带着重复(或者几乎重复)的代码.数据,或两者.其结 ...

  7. 《Effective STL》重读笔记整理

    最近有闲,在工作之余重读了<effective STL>一书,并通过 twitter 记了一下笔记,今天整理收集到这里. twitter 真的非常适合记读书笔记,哈哈,以后要好好地发扬.另 ...

  8. 【绝版C++书籍】《Effective STL》读书笔记

    <Effective STL>读书笔记 写在前面 0<Effective STL>中可能过时的内容 1 容器 第1条:慎重选择容器类型. 第2条:不要试图编写独立于容器类型的代 ...

  9. Effective STL 50条有效使用STL的经验笔记

    Scott Meyers大师Effective三部曲:Effective C++.More Effective C++.Effective STL,这三本书出版已很多年,后来又出版了Effective ...

最新文章

  1. PyTorch入门学习(二):Autogard之自动求梯度
  2. 【tensorboard】从tensorboard上看出模型是否存在过拟合
  3. PLSQL乱码TNS-12557: protocol adapter not loadable解决
  4. python 时间序列分析之ARIMA(不使用第三方库)
  5. [TypeScript] Export public types from your library
  6. 【BZOJ1922】【Tyvj1736】【codevs2129】大陆争霸,无语最短路
  7. TCN-时间卷积网络
  8. 动漫头像1000张萌妹子图片,可以做高清头像壁纸
  9. 16 计算二叉树叶子结点数目(耿 6.14)
  10. spark报错:Cannot overwrite a path that is also being read from.
  11. Keep不甘做“工具人”
  12. 回车、换行、空格的ASCII码值(不同OS平台下文件换行定义)
  13. Python编程IDE的选择
  14. 送给23岁的风华年少
  15. (附源码)Springboot宠物领养系统毕业设计241104
  16. DQN(Deep Q Network)及其代码实现
  17. 新手程序员首份工作月薪三千,网友:3000元?你是在丢码农的脸吗
  18. 超级文案撰写技巧之对比写法
  19. 如果有一天我不更新博客了
  20. RedHat Linux 9.0的安装+下载+入门指南(图文并茂)

热门文章

  1. 分布式内存数据库---Redis操作String、list、set、hash和Zset
  2. PageRanke算法
  3. pch在c语言中占内存字节数,c语言期末测试题(附答案)
  4. ACL 2020 | 基于稠密段落检索的开放域问答系统技术
  5. IJCAI 2019 论文解读 | 基于超图网络模型的图网络进化算法
  6. Wasserstein距离在生成模型中的应用
  7. 综述 | 知识图谱向量化表示
  8. LightOJ 1401 No More Tic-tac-toe 博弈论SG打表
  9. CentOS系统中使用yum快速安装python3
  10. 元件库导入_Axure RP9【元件库的学习】