- 注意参数名左右的括号(就像f的第二种声明中的d)和单独的括号(正如本例)之间的区别。参数名左右的括号被忽略,但单独的括号指出存在一个参数列表:它们声明了存在指向函数的指针的参数。// int g(double (*pf)()); int g(double pf()); int g(double ()); 等价!
list<int> data(istream_iterator<int>(dataFile), istream_iterator<int>());这声明了一个函数data,它的返回类型是list<int>。这个函数data带有两个参数:
- 第一个参数叫做dataFile。它的类型是istream_iterator<int>。dataFile左右的括号是多余的而且被忽略。
- 第二个参数没有名字。它的类型是指向一个没有参数而且返回istream_iterator<int>的函数的指针。
- vector承诺了与数组具有相同的潜在内存分布。让C风格API把数据放入一个vector,然后拷到你实际想要的STL容器中的主意总是有效的;(不能直接将数组API复制到string、list,可以通过vector进行中转,先存入vector,再存入其他容器);
- 分割问题暗示了把一个派生类对象插入基类对象的容器几乎总是错的。一个使拷贝更高效、正确而且对分割问题免疫的简单的方式是建立指针的容器而不是对象的容器。为了避免内存泄露,记得boost::shared_ ptr;
- 相等:基于operator==,如果“x == y”为真,则相等
等价:基于比较函数,如果比较函数是<,则!(w1 < w2)&&!(w2<w1)为真,则等价。
- 为指针的“关联容器”指定"比较类型":template <class _Key, class _Compare, class _Alloc>class set; //默认为less
- 无论何时你建立一个指针的标准关联容器,你必须记住容器会以指针的值排序。这基本上不是你想要的,所以你几乎总是需要建立自己的仿函数类作为比较类型。如set<string*, less<string*> > ssp; 不能自动按字符串排序,需要一个用于比较的仿函数模板struct DereferenceLess {
template <typename PtrType>
bool operator()(PtrType pT1,// 参数是值传递的,
PtrType pT2) const// 因为我们希望它们
{ // 是(或行为像)指针
return *pT1 < *pT2;
}
};
- 永远让比较函数对相等的值返回false:否则两个相等的值将不等价,会破坏容器!(“关联容器”)。比较才有"<",且不要取反操作。
- 考虑用有序vector代替关联容器:如insert,erase,assign,构造函数。
- 不能修改set的key
已经记住的:
- 使用reserve来避免不必要的重新分配,针对string、vector;
- 用empty来代替检查size()是否为0;
- 永不建立auto_ptr的容器;
- sizeof(string)因实现版本不同而不确定;
- 唯一从容器中除去一个元素的方法是在那个容器上调用一个成员函数,而且因为remove无法知道它正在操作的容器,所以remove不可能从一个容器中除去元素。这解释了另一个令人沮丧的观点——从一个容器中remove元素不会改变容器中元素的个数:
- 注意以下区别:static_cast<Employee>(a) --- 会产生临时匿名对象; static_cast<Employee &>(a)
- 使用“交换技巧”来修整过剩容量: string(s).swap(s);// 在s上进行“收缩到合适”,string(s)会创建了一个临时对象; string().swap(s); // 清除s而且最小化它的容量
- class Widget {...}; // 假设Widget有默认构造函数 Widget w();它声明了一个叫作w的没有参数且返回Widget的函数。
- 使用成员函数形式的find、count、lower_bound等等,而不是同名的算法,因为这些成员函数版本提供了和其它成员函数一致的行为。由于相等和等价间的差别,算法不能提供这样的一致行为。(算法使用的是“相等”)
复制:
- 拷贝一个容器到另一个同类型的容器:operator=就是选择的赋值函数
- 复制容器的部分内容到新容器:assign(vector,string,deque和list)
删除:
一、去除一个容器中有特定值的所有对象:
- 如果容器是vector、string或deque,使用erase-remove惯用法。不能直接在指针容器上做remove方法,会导致内存泄露!
c.erase(remove(c.begin(), c.end(), 1963), // 当c是vector、string c.end()); // 或deque时, // erase-remove惯用法 // 是去除特定值的元素 // 的最佳方法
- 如果容器是list,使用list::remove。
- 如果容器是标准关联容器,使用它的erase成员函数。
二、去除一个容器中满足一个特定判定式的所有对象:
- 如果容器是vector、string或deque,使用erase-remove_if惯用法。
- 如果容器是list,使用list::remove_if。
- 如果容器是标准关联容器,使用remove_copy_if和swap(效率低下,不采用),或写一个循环来遍历容器元素,当你把迭代器传给erase时迭代器失效,记得后置递增它。
三、如果自己写循环删除指定对象,注意要点如下:
1. 为了避免迭代器失效,在循环内:
- 如果容器是标准序列容器,写一个循环来遍历容器元素,每当调用erase时记得都用它的返回值更新你的迭代器。
- 如果容器是标准关联容器,写一个循环来遍历容器元素,当你把迭代器传给erase时记得后置递增它。
2. 别忘了先删除“指针容器”中的元素所指对象,避免内存泄露。或者使用智能指针:
- 在应用erase-remove惯用法之前先删除指针并设置它们为空,然后除去容器中的所有空指针;
- 使用智能指针shared_ptr;