zoukankan      html  css  js  c++  java
  • Effective STL 学习笔记 32 ~ 33

    Effective STL 学习笔记 32 ~ 33

    1 记得 Remove 后要 Erase

    Item 9 中已经提到过,如果真的想要用 remove 从容器中删除元素,必须要在 remove 之后使用 erase 。其原因在于: remove 接受的参数是通用的迭代器,而不是容器,它不知道容器的任何信息,也就无法从容器中删除元素: remove doesn't really remove anything, because it can't.

    remove 只保证在其返回的迭代器之前的元素为有效数据(符合条件的数据),但它既无法删除被 remove 的数据,也不能保证返回的迭代器之后的数据位无效数据(不符合条件的数据)。这一点与某些容器内置的 remove member function 不一样:这些 member function 会真正的把数据删除掉:

    // For vector, we have to call erase after remove.
    vector<int> v;
    // ....
    vector<int>::iterator endPos = remove(v.begin(), v.end(), 99); // Remove 99 from vector, returns last valid position.
    v.erase(posEnd, v.end()); // Erase all elements after posEnd.
    
    // For list, the member function remove is enough:
    list<int> l;
    //...
    l.remove(99); // this will erase all 99 in the list.
    

    2 remove, container, pointer

    Item 6 中提到,在容器中放置对象指针容易混乱,这里如果对存放指针的容器调用 remove-erase idom 的话,会发生什么事情?

     1: class Widget
     2: {
     3: public:
     4:     Widget();
     5:     virtual ~Widget();
     6:     bool IsCertified();
     7: };
     8: 
     9: vector<Widget*> v;
    10: 
    11: // push lots of widget pointers to v.
    12: 
    13: v.erase(remove(v.begin(), v.end(), not1(mem_fun(&Widget::IsCertified))), v.end());
    

    内存泄露。

    那么将第 13 行换成下面的表达式呢?

    14: vector<Widget*> endPos = remove(v.begin(), v.end(), not(mem_fun(&Widget::IsCertified)));
    15: for_each(endPos, v.end(), [](Widget* pw){if(pw) delete pw;});
    16: v.erase(endPos, v.end());
    

    第 14 行将所有的 endPos 之后的指针先释放,然后再去 erase。前面刚刚提过, remove 不会保证返回的迭代器之后的元素都为无效值,第 14 行有可能会将本该保留的对象给释放掉,还有可能会将该释放的不释放。结果可能会 Crash 或者内存泄露。

    我们应该保证在 remove 过程中,一旦发现不合要求的数据,马上将其删除,例如下面的例子:

    #include <vector>
    #include <iterator>
    #include <algorithm>
    #include <iostream>
    #include <stdio.h>
    
    using namespace std;
    
    class Widget
    {
    public:
        Widget(int i);
        virtual ~Widget();
        bool IsCertified();
        void Show();
    private:
        int m_i;
    };
    
    /* See description in header file. */
    Widget::Widget(int i)
            : m_i(i)
    {
    }
    
    /* See description in header file. */
    Widget::~Widget()
    {
        printf ("Deleting Obj: %p, value: %d
    ", this, m_i);
    }
    
    /* See description in header file. */
    bool Widget::IsCertified()
    {
        return m_i % 2 == 0;
    }
    
    /* See description in header file. */
    void Widget::Show()
    {
        printf ("	Obj: %p, value: %d
    ", this, m_i);
    }
    
    bool DeleteIfUncitified(Widget* p)
    {
        if (p && !p->IsCertified())
        {
            delete p;
            return true;
        }
        return false;
    }
    
    int main(int argc, char *argv[])
    {
        vector<Widget*> v;
        for (int i = 0; i < 20; ++i)
        {
            Widget* p = new Widget(i);
            v.push_back(p);
        }
    
        random_shuffle(v.begin(), v.end());
    
        printf ("Before remove, size: %lu, contents:
    ", v.size());
        for_each(v.begin(), v.end(),
                 [](Widget* p){
                     if (p) p->Show();
                     else printf("Obj is Null");});
        printf ("
    Now removing...
    ");
        v.erase(remove_if(v.begin(), v.end(), DeleteIfUncitified), v.end());
        printf ("
    After remove, size: %lu, contents:
    ", v.size());
        for_each(v.begin(), v.end(),
                 [](Widget* p){
                     if (p) p->Show();
                     else printf("Obj is Null");});
    
        return 0;
    }
    

    其输出为:

    
    Welcome to the Emacs shell
    
    ~/tmp $ ./test
    Before remove, size: 20, contents:
            Obj: 0x7f8b31c038d0, value: 19
            Obj: 0x7f8b31c03870, value: 3
            Obj: 0x7f8b31c039e0, value: 14
            Obj: 0x7f8b31c039f0, value: 15
            Obj: 0x7f8b31c03890, value: 10
            Obj: 0x7f8b31c03850, value: 2
            Obj: 0x7f8b31c03900, value: 6
            Obj: 0x7f8b31c038b0, value: 17
            Obj: 0x7f8b31c03920, value: 8
            Obj: 0x7f8b31c038a0, value: 4
            Obj: 0x7f8b31c039c0, value: 12
            Obj: 0x7f8b31c03910, value: 7
            Obj: 0x7f8b31c038f0, value: 5
            Obj: 0x7f8b31c039b0, value: 11
            Obj: 0x7f8b31c03860, value: 1
            Obj: 0x7f8b31c03880, value: 9
            Obj: 0x7f8b31c03840, value: 0
            Obj: 0x7f8b31c03a00, value: 16
            Obj: 0x7f8b31c039d0, value: 13
            Obj: 0x7f8b31c038c0, value: 18
    
    Now removing...
    Deleting Obj: 0x7f8b31c038d0, value: 19
    Deleting Obj: 0x7f8b31c03870, value: 3
    Deleting Obj: 0x7f8b31c039f0, value: 15
    Deleting Obj: 0x7f8b31c038b0, value: 17
    Deleting Obj: 0x7f8b31c03910, value: 7
    Deleting Obj: 0x7f8b31c038f0, value: 5
    Deleting Obj: 0x7f8b31c039b0, value: 11
    Deleting Obj: 0x7f8b31c03860, value: 1
    Deleting Obj: 0x7f8b31c03880, value: 9
    Deleting Obj: 0x7f8b31c039d0, value: 13
    
    After remove, size: 10, contents:
            Obj: 0x7f8b31c039e0, value: 14
            Obj: 0x7f8b31c03890, value: 10
            Obj: 0x7f8b31c03850, value: 2
            Obj: 0x7f8b31c03900, value: 6
            Obj: 0x7f8b31c03920, value: 8
            Obj: 0x7f8b31c038a0, value: 4
            Obj: 0x7f8b31c039c0, value: 12
            Obj: 0x7f8b31c03840, value: 0
            Obj: 0x7f8b31c03a00, value: 16
            Obj: 0x7f8b31c038c0, value: 18
    ~/tmp $ 
  • 相关阅读:
    底图与蒙版的过渡效果transition
    消除blur属性的边框
    jquery ajax实例教程和一些高级用法
    常用js正则表达式大全
    HTML5 + JS 调取摄像头拍照下载
    JS运动框架
    JS 实现AJAX封装(只限于异步)
    事件委托详解
    JS 实现随机验证码功能
    利用JS调取电脑摄像头,实现拍照功能
  • 原文地址:https://www.cnblogs.com/yangyingchao/p/3426099.html
Copyright © 2011-2022 走看看