玩命加载中 . . .

STL_1


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才真正删除

同为序列化容器的dequestring也需要使用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,两种方式都可以,一般用序列化容器的方式


文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录