有效的STL学习记录

10.25
{
 1. 你不可能在不知道怎么写自己的函数对象的情况下有效地使用STL
 2. 讨论STL而没有提及引用计数是几乎不可能的, 基于指针的容器的设计几乎总要导致引用计数
 3. STL编程的四大金刚:容器、迭代器、算法、函数对象 
 }
{
 1. 仔细选择你的容器
 {
  1.1 有哪些容器?
  标准STL序列容器:vector、string、deque和list。
  标准STL关联容器:set、multiset、map和multimap。
  非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一个重型字符串。
  非标准关联容器hash_set、hash_multiset、hash_map和hash_multimap。
  
  标准非STL容器,包括数组、bitset、valarray、stack、queue和priority_queue。
  
  基于连续内存的容器 ---vector, string , deque
  基于非连续内存的容器==基于节点的容器----list map set 
  
  连续内存的容器,进行插入、删除操作后----所有迭代器失效
  deque是唯一一个“在迭代器失效时不会使它的指针和引用失效”的标准STL容器
  
  ***: vector 不能存储bool?
 }
 2. 小心“容器无关代码”----不同的操作并不是在所有容器上都有相同的意义。
 {
  2.1 面对事实,“容器无关的代码” 难度大,而且没有必要。容器就是为不同应用而生的,它们一开始就没有被设计为可互换的。  
  2.2 如果有必要进行容器的更换,则用typedef,对容器和迭代器进行 typedef.
  2.3 将容器作为 class的私有成员,利用class封闭它,并且,仅提供必要的接口,有可能会写出容器无关的代码。
 }
 3. 务必让容器中的对象的拷贝操作轻量且正确
 {
  3.1 拷进去,拷出来,是stl的行为方式。
  3.2 可以考虑不拷贝对象,而是拷贝对象的指针。 但也要注意指针带来的新问题---auto_ptr, new之后的内存释放 。
 }
 4. 用empty 代替 size() == 0 来判断一个容器是否为空。
 {
  4.1 主要考虑到时间复杂度,empty -- 常数时间, size 某些情况下是线性时间
 }
 5. 使用容器的区间成员函数,而不要对其单个元素进行循环操作。
 {
  5.1 对迭代器区间操作的成员函数,效率高,代码简洁如:assign, insert,不易出错
  5.2 也要避免copy 算法,它往往也是用循环来对容器中的单元元素进行操作
 }
 6. 
 7.当容器中装入了new得到的指针时,在销毁容器前一定要delete元素。
 {
  7.1 用for_each(begin_itr, end_itr, delete_func) 代替 自己写的 for 循环是个好主意。
  7.2 从没有虚析构函数的类,公有继承得到子类是一个禁忌,切记!
  7.3 类型演绎下降---将模板定义--从定义类模板,下放到定义类的模板成员函数。
  7.4 如果在容器装入new的指针之后,在for_each delete指针之前,程序招聘异常,依然会泄漏内存,好的解决办法是用智能指针 。但是不可以用auto_ptr,应该用tr1::shared_ptr, 或者boost::shared_ptr!
 }
 8. 不要建立auto_ptr的容器。
 {
  8.1 当拷贝一个auto_ptr1 到 auto_ptr2时,新的auto_ptr2将接管所指向的对象,原来的auto_ptr1将被置为NULL。也就说,拷贝一个auto_ptr会改变它的值。
  auto_ptr<SomeClass> p1(new SomeClass);
  auto_ptr<SomeClass> p2(p1); // p2 指向刚刚new的对象, p1则为NULL
  p1 = p2; // 现在p1指向了对象, 而p2 又变成了null
  
 }
 9. 在删除选项中仔细选择
 {
  9.1 仔细选择的原因是:容器的删除操作动作各不同。 对于内存连续容器,一般用erase-remove方法。
 }
 10.
 11.
 12. 使用容器时的多线程安全考虑
 {
  12.1 用Lock类,构造时锁定互斥量,析构时解锁,C++保证,退出代码块时,临时变量的析构函数被调用,即使发生异常,也会调用 。
 }
 13. 用vector string,而不是动态数组
 {
  它们的易用性无需赘述,有些可能的考虑:
  13.1 注意size(), resize(), capacity((), reserve() 几个成员函数的差别。
  13.2 要考虑到vector 增长时,开辟空间、拷贝、销毁原对象、收回内存的开销,有时候,可以用reserve提前预留出一定大小 。
 }
 14. 
 15.
 16. 将vector string 与C 风格的API共用---如何和平共处?
 {
  16.1 用&v[0] 获取vector第0个元素的地址,传给C指针 ,----但是要保证vector非空,否则致使错误。
       ----另外,不要试图用v.begin()来代替&v[0],尽管有些时候那也是对的---因为有时候是错的。
  16.2 用.c_str 将string 传给 char * c风格参数
 }
 17. 学会使用“交换技巧”来使窗口“收缩到合适”容量。
 {
  vector<SomeClass> (ins).swap(ins);
  
  string (str1).swap(str1)
  
  .操作符前都是构造了一个临时容器,且由原容器中有效元素填充,再交换一下,原容器变成合适大小,旧窗口被销毁,多余容量被释放。
 }
 18. 不能使用vector<bool>
 {
  18.1 vector<bool>并不真正保存bool变量,而是会将bool变量以bit位的形式保存,以节省空间。
  18.2 要用bool的容器,可以用deque<bool>。或者用bitset----非标准C++的一个库。
 }
 对于关联容器:
 19. 必须明白“相等”与“等价”之间的差别。
 {
  19.1 相等: == ,a==b
  19.2 等价: !(a<b) && !(b<a) ,----关联容器使用的是等价,而不是相等。
 }
 20. 为指针的关联容器指定其特有的比较函数对象
 {
  20.1 建立一个指针的关联容器,容器会为指针的值---而不是指针所指向的值 ---排序。
  20.2 某些情况下---比如 set, 需要显示的“函数对象”,函数则不行----这取决于模板中定义的第二个参数是一个类型---函数不是类型。
  20.3 对于智能指针、迭代器,也是以此类推。
  20.4 可以定义一个类的模板成员函数,可泛用于各种指针的比较 。
 }
 21. 小心的设计比较函数,使其对相等的值返回false!
 {
  21.1 我们通常需要正确的实现: < 操作,它对两个相等的值,绝对应该返回false! 切忌不可用”<=“的比较函数。
  21.2 另外,我们不能用 一个已经定义的 < 操作的取反操作,来定义 > ,因为那漏掉了 =。
  21.3 这里涉及到的一个概念是”严格的弱序化“
 }
 22. 避免“原地” 修改 set 或者 map 的键。
 {
  22.1 map的键是const,不可修改, set的键不是const,可以修改
  22.2 不要修改set的键,那会引起未定义的结果----但是可以修改set中元素的非键的成员。
  22.3 欲修改set中的键时,将 (*element) 转换为可修改时,用const_cast, 而决不要用static_cast.因为后者建立了副本,后面的进一步操作是在副本上操作。
 }
 23. 考虑用vector代替关联容器
 {
  23.1 有背于直觉,有序的--vector往往能提供比关联容器的log N时间复杂度更好的查找----标准关联容器的典型实现---平衡二叉查找树
  23.2 在有序vector中存储数据很有可能比在标准关联容器中保存相同的数据消耗更少的内存;当页面错误
值得重视的时候,在有序vector中通过二分法查找可能比在一个标准关联容器中查找更快。
  23.3 vector的插入、删除是昂贵的,只有确定我们的应用中,数据的查找与插入删除不会混在一起时,用有序的vector才有意义 。
  23.4 如果用vector 模拟 map或者 multimap,需要细心对待其中的键----值。这里不应该有const key!
 }
 24. 对于map,理解 operator[] 与 insert函数之间的效率差异
 {
  24.1 对于直接了当的插入,insert更高效----[]有产生pair副本、构造及析构该副本的成本
  24.2 对于更新已有的键值,【】更高效。----可以设计更好的实现,结合两者的优点 。
 }
 25. 熟悉非标准的散列容器
 {
  25.1 散列容器,用于比较键的算法可以用==,可以不用<,因为它不需要保持有序----这与基于树的标准关联容器不同。
  25.2 
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值