7 如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉
如果容器中存放指针,记得要在结束后释放指针的资源
class Foo {};
vector<Foo*> vf;
for (int i = 0; i < 5; i++) {
vf.push_back(new Foo());
}
for (auto it = vf.begin(); it != vf.end(); ++it) {
delete *it;
}
可以用for_each
,需要传入一个可调用对象(删除器)
template<class T>
struct DeleteObject: public unary_function<const T*, void> {
void operator()(const T *ptr) {
delete ptr;
}
};
for_each(vf.begin(), vf.end(), DeleteObject<Foo>());
或者使用智能指针
vector<shared_ptr<Foo>> vf;
for (int i = 0; i < 5; i++) {
vf.push_back(shared_ptr<Foo>(new Foo()));
}
STL 容器很智能,但没有智能到知道是否该删除自己所包含的指针的程度。当你使用指针的容器,而其中的指针应该被删除时,为了避免资源泄漏,你必须或者用引用计数形式的智能指针对象(比如shared_ptr)代替指针,或者当容器被析构时手动删除其中的每个指针
9 慎重选择删除元素的方法
标准库函数remove
只是用类似双指针的方法将不需要删除的元素移到前面,然后返回指向第一个需要删除的元素的迭代器,并没有真正删除元素,所以还需要用erase
才真正删除
同为序列化容器的deque
和string
也需要使用erase-remove
vector<int> nums = {1, 2, 3, 4, 1};
// auto it = remove(nums.begin(), nums.end(), 1); // 2 3 4 4 1
// cout << (it - nums.begin()) << endl; // 3
nums.erase(remove(nums.begin(), nums.end(), 1), nums.end()); // 2 3 4
list
应该使用其remove
成员函数
list<int> nums = {1, 2, 3, 4, 1};
nums.remove(1); // 2 3 4
关联容器(set、multiset、map、multimap)应该使用其erase
成员函数
set<int> nums = {1, 2, 3, 4};
nums.erase(1); // 2 3 4
如果是要删除满足某个条件的元素
对于序列化容器,把remove
换成remove_if
就可以了
bool badValue(int x) {
return x <= 1;
}
vector<int> nums = {1, 2, 3, 4, 1};
nums.erase(remove_if(nums.begin(), nums.end(), badValue), nums.end()); // 2 3 4
---
nums.remove_if(badValue); // 这里是list
对于关联容器,需要遍历容器,找到满足条件的删除它
因为调用erase(it)
之后迭代器就失效了,所以需要使用后置递增的方式传递迭代器,这样传入erase
的是it
的旧值,而递增之后的it
是有效的
set<int> nums = {1, 2, 3, 4};
for (auto it = nums.begin(); it != nums.end(); /* 不在这里递增 */ ) {
if (badValue(*it)) nums.erase(it++);
else ++it;
}
如果除了删除之外,还要做其他事情,打印日志等
关联式容器可以在循环内很容易做到
for (auto it = nums.begin(); it != nums.end(); /* 不在这里递增 */ ) {
if (badValue(*it)) {
cout << "erase: " << *it << endl; // 打印日志
nums.erase(it++);
}
else ++it;
}
对于序列化容器(vector、deque、string)调用erase
不仅会使指向被删除元素的迭代器无效,也会使被删除元素之后的所有迭代器都无效
要利用erase
的返回值,一旦erase
完成,它是指向紧随被删除元素的下一个元素的有效迭代器
vector<int> nums = {1, 2, 3, 4, 1};
for (auto it = nums.begin(); it != nums.end(); /* 不在这里递增 */ ) {
if (badValue(*it)) {
cout << "erase: " << *it << endl;
it = nums.erase(it); // 接收返回值,指向下一个元素的迭代器
}
else ++it;
}
对于list
,两种方式都可以,一般用序列化容器的方式