Reading Notes - Effective STL Note 9 - Choose the Method of deleting elements carefully

Fork me on GitHub
  

结论

书里对于要删除容器内元素的情况分成了下面三类:

  • 删除特定值的所有对象
  • 删除满足特定条件的对象
  • 删除对象同时还需要其它操作

对于每一类都有不同的方法来处理, 下面分别介绍。

删除特定值的所有对象

  • 对于vector,stringdeque使用erase-remove

这一条其实对于连续内存的容器都适用,一般使用下面方法:

c.erase(remove(c.begin(), c.end(), removeVal), c.end);

其中removealgorithm库中提供的方法,功能是使用move assignment来将不是removeVal的元素移到前面,最后返回前面不是removeVal的元素组成的新范围的end迭代器。然后可以使用容器提供的erase函数来删掉remove返回迭代器后面所有值。

  • 对于list,则使用list::remove

list使用上面的方法也是适用的,但是使用list成员函数remove更加有效:

c.remove(removeVal);
  • 对于关联容器set/map,则使用set::erasemap::erase

对于关联容器set/map(以及multiset/multimap)既没有remove成员函数,也不能使用remove函数。正确的方法是调用成员函数erase:

c.erase(removeVal);

只删除满足特定条件的对象

这类问题描述是将上面直接给定要删除的值,现在则是删除满足下面条件的对象:

bool badValue(int );
  • 对于vector,stringdeque使用erase-remove_if, 对于list,则使用list::remove_if

比较简单, 我们可以直接将上面的remove算法换成remove_if:

c.erase(remove_if(c.begin(), c.end(), removeVal), c.end);
c.remove_if(badValue);
  • 对于关联容器set/map , 我们不能简单地使用erase, 可以使用remove_copy_ifswap
     AssocContainer<int> c;
     AssocContainer<int> goodValues;
     remove_copy_if(c.begin(), c.end(), 
                   inserter(goodValues, goodValues.end()), 
                   badValue);
     c.swap(goodValues);

这种方法直接简单但是效率比较低,因为要移动元素。其中remove_copy_if功能是将c中满足badValue的元素复制到goodValues中。

或者循环遍历时对于传给erase的迭代器要进行后缀递增

    for(AssocContainer<int>::iterator i = c.begin(); i != c.end(); ) {
      if( badValue(*i) )
        c.erase(i++);
      else
        ++i;
    }

其中关键点就在于传递给erase的迭代器要使用后缀递增, 而不能放在for循环里, 因为删除元素之后,指向该元素的所有迭代器都变得无效。

删除对象同时还需要其它操作

这种情况其实是在上面又加了一条约束, 对于关联容器,我们只需要添加相应操作即可。 而对于顺序容器,则必须采用类似关联容器的方法。

  • 对于vector,stringdequelist标准序列容器,需要循环遍历容器中元素,需要注意的是每次调用erase时,需要用返回值更新迭代器
for(SeqContainer<int>::iterator i = c.begin(); i != c.end(); ) {
  if( badValue(*i) )
    // other operation
    i = c.erase(i);
  else
    ++i;
}

关键点在于删除时需要使用erase返回的迭代器来更新循环迭代器

  • 对于关联容器set/map,循环遍历时对于传给erase的迭代器要进行后缀递增
for(AssocContainer<int>::iterator i = c.begin(); i != c.end(); ) {
  if( badValue(*i) )
    // other operation
    c.erase(i++);
  else
    ++i;
}

参考

  
志飞 /
Published under (CC) BY-NC-SA