条款1:仔细选择你的容器
了解各种容器的实现方法,知道各种容器的内存管理方式、各种操作所对应的底层操作,然后根据需要选择恰当的容器。
条款2:小心对“容器无关代码”的幻想
各种容器支持的操作集合不同、各容器相同操作的特性不同。
条款3:使容器里对象的拷贝操作轻量而正确
一个使拷贝更高效、正确而且对分割问题免疫的简单的方式是建立指针的容器而不是对象的容器。
条款4:用empty来代替检查size()是否为0
不管发生了什么,如果你用empty来代替检查是否size() == 0,你都不会出错。所以在想知道容器是否包含0个元素的时候都应该调用empty。另外,有的容器调用size()耗时比较长。
条款5:尽量使用区间成员函数代替它们的单元素兄弟
看懂这行代码:v1.assign(v2.begin() + v2.size() / 2, v2.end());
几乎所有目标区间被插入迭代器指定的copy的使用都可以用调用的区间成员函数的来代替。
区间构造、区间插入、区间删除、区间赋值。
条款6:警惕C++最令人恼怒的解析
语法混乱。
条款7:当使用new得指针的容器时,记得在销毁容器前delete那些指针
记得new完了要delete,但管理方法可以选择更多。
struct DeleteObject {
template<typename T>
void operator()(const T* ptr) const { delete ptr; }
}
for_each(dssp.begin(), dssp.end(),DeleteObject());
typedef boost::shared_ ptr<Widget> SPW;
vector<SPW> vwp;
for (int i = 0; i < SOME_MAGIC_NUMBER; ++i)
vwp.push_back(SPW(new Widget));
条款8:永不建立auto_ptr的容器
auto_ptr的容器(COAPs)是禁止的。试图使用它们的代码都不能编译。智能指针的容器是很好的,
条款50描述了你在哪里可以找到和STL容器咬合良好的智能指针。只不过auto_ptr不是那样的智能指针。
条款9:在删除选项中仔细选择
c.erase(remove_if(c.begin(), c.end(), badValue), c.end());// 当
c是vector、string或
deque时这是去掉badValue返回真的对象的最佳方法
c.remove_if(badValue);
// 当
c是list时这是去掉badValue返回真的对象的最佳方法
去除一个容器中有特定值的所有对象:
如果容器是
vector、string或deque,使用erase-remove惯用法。
如果容器是
list,使用list::remove。
如果容器是标准关联容器,使用它的
erase成员函数。
去除一个容器中满足一个特定判定式的所有对象:
如果容器是
vector、string或deque,使用erase-remove_if惯用法。
如果容器是
list,使用list::remove_if。
如果容器是标准关联容器,使用
remove_copy_if和swap,或写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。
在循环内做某些事情(除了删除对象之外):
如果容器是标准序列容器,写一个循环来遍历容器元素,每当调用
erase时记得都用它的返回值更新你的迭代器。
如果容器是标准关联容器,写一个循环来遍历容器元素,当你把迭代器传给
erase时记得后置递增它。
条款10:注意分配器的协定和约束
把你的分配器做成一个模板,带有模板参数
T,代表你要分配内存的对象类型。
提供
pointer和reference的typedef,但是总是让pointer是T*,reference是T&。
决不要给你的分配器每对象状态。通常,分配器不能有非静态的数据成员。
记得应该传给分配器的
allocate成员函数需要分配的对象个数而不是字节数。也应该记得这些函数返回T*指针(通过pointer typedef),即使还没有T对象被构造。
一定要提供标准容器依赖的内嵌
rebind模板。
条款11:理解自定义分配器的正确用法
自定义分配器,暂时不打算这样做,俺水平不够。
条款12:对STL容器线程安全性的期待现实一些
多个读取者是安全的。对不同容器的多个写入者是安全的。Stl的线程安全性由用户自己实现。