01.慎重选择容器类型
选择容器原则:需要考虑元素的排序情况,是否与标准相符,迭代器能力,元素布局,与C的兼容性,查找速度,引用计数,插入删除对事物语义的支持,某些操作是否会使迭代器无效,内存分配策略。
vector
需要使用随机迭代器
容器中布局需要与C兼容
deque
需要使用随机迭代器
当大多数插入在头部和尾部时
在尾部插入不会是迭代器,指针,引用变为无效
string
需要使用随机迭代器
介意使用引用计数计数,避免使用string,rope。string不可行
介意在容器上使用swap导致迭代器,指针,引用变成无效。string不可行
list
需要频繁的在中间插入删除
当大多数插入在头部和尾部时
对多个元素的插入删除需要事务语义
hash
查找速度是关键因素,选择优先级为hash->排序的vector->标准关联容器
关注元素的排序不可行
序列容器(vector string deque list slist rope)
需要在容器的任何位置插入新元素
关联容器
在容器中任意位置插入元素不可行
基于节点的容器(list,slist,关联容器,hash)
在单个节点插入删除时需要回滚能力
使迭代器,指针,引用变为无效的次数最少
元素插入删除时,避免移动容器中原来的元素
连续内存容器(vector,deque,string)
02.不要试图编写独立于容器类型的代码
原因:
- 不同容器的函数集不同
- 不同容器的同名函数返回值不同
- 不同容器使迭代器失效的规则不同
- 所编写代码只能使用这些容器的交集
03.确保容器中的对象拷贝正确而高效
注意点:
- 存放基类对象的容器,向其中插入派生类对象,会导致剥离。
- 使拷贝动作高效,正确,并防止剥离问题发生的一个简单办法使在容器中包含指针而不是对象。
04.调用empty而不是检查size()是否为0
原因:
- 使用empty性能优于判断size()是否为0
- empty是常数时间,有些list实现可能是线性时间
- list的size()和splice()只有一个可实现为常数时间。
05.区间成员函数优先于与之对应的单元素成员函数
遗留问题:
vector::assign的实现方式
结论:
所有通过利用插入迭代器来限定目标区间的copy调用,都可以替换为对区间成员函数的调用。
使用区间函数避免频繁调用分配子,提升性能。
区间成员函数有:构造函数,区间插入,区间删除,区间赋值。
06.当心C++编译器最烦人的分析机制
以标准输入装置完成初始化操作
以下为错误写法:
std::deque<int> c(std::istream_iterator<int> (std::cin), std::istream_iterator<int>());
以上c被解析为函数声明。返回值为std::deque<int>,第一个参数型别为std::istream_iterator,参数名为cin。第二个参数无名称,型别是一个函数,不接受任何参数,返回值为std::istream_iterator<int>。
正确写法如下:
std::deque<int> c((std::istream_iterator<int> (std::cin)),(std::istream_iterator<int>()));
07.如果容器中包含了通过new操作符创建的指针,切记在容器对象析构前将指针delete掉
void doSomething() { vector<Widget*> vwp; // do something // for (vector<Widget*>::iterator i = vwp.begin(); i!= vwp.end(); ++i) delete *i }
以上代码问题:在do something部分发生异常,则会造成资源泄露,vector中的动态申请的Widget不会被释放。
解决方法:使用boost库中的share_ptr智能指针。发生异常时,栈中对象的析构函数均会被调用。
删除指针的仿函数模板
class DeleteObject { template<typename T> void operator()(const T* ptr) const { delete ptr; } }
08.切勿创建包含auto_ptr的容器对象
09.慎重选择删除元素的方法
删除指定值
vector,string,deque:c.erase(remove(c.begin(), c.end(), value));
list:c.remove(value);
set,multiset,map,multimap:c.erase(value);基于等价(<)进行删除
删除判别式为true的值
vector,string,deque:c.erase(remove_if(c.begin(), c.end(), judge));
for (SeqContainer<int>::iterator i = c.begin; i != c.end();) { if (judge(*i)) { // 处理*i i = c.erase(*i); } else ++i; }
list:c.remove_if(judge);
set,multiset,map,multimap:
remove_copy_if;c.swap
AssocContainer<int> c; for (AssocContainer<int>::iterator i = c.begin(); i != c.end();) { if (judge(*i)) c.erase(i++) else ++i }
11.切勿对STL容器的线程安全性有不切实际的依赖
对STL支持多线程的最多期望:
- 多个线程度时安全的
- 多个线程对不同容器做写入操作时安全的