什么是非空STL擦除的安全等价物?

时间:2008-10-20 09:31:55

标签: c++ stl iterator hashmap

假设我有一个hash_map和一个像

这样的代码
// i is an iterator
i = hash_map.erase(i)

但是GCC的STL不会在擦除中返回迭代器,而是一个空白。现在是像

这样的代码
hash_map.erase(i++)

安全(即不会使迭代器无效或做任何其他意外或不愉快的事情)?请注意这是一个hash_map。

3 个答案:

答案 0 :(得分:6)

是的,这是安全的,因为在删除当前值之前,i的值将被设置为下一个值。

根据SGI documentation about hashed containers失效不会发生非擦除元素,甚至也不会调整大小(没有关于插入是否会导致调整大小的说法,所以要小心我承认作为一种可能性)---但在后一种情况下,迭代顺序将会改变。但这不适用于此,除非您在遍历或其他事情期间不遗余力地调整容器大小。 : - )

答案 1 :(得分:2)

您可以封装擦除,为您使用的所有容器提供相同的界面:

namespace detail {
template<typename Container, typename R>
struct SelectErase {
  // by default, assume the next iterator is returned
  template<typename Iterator>
  Iterator erase(Container& c, Iterator where) {
    return c.erase(where);
  }
};
// specialize on return type void
template<typename Container>
struct SelectErase<Container, void> {
  template<typename Iterator>
  Iterator erase(Container& c, Iterator where) {
    Iterator next (where);
    ++next;
    c.erase(where);
    return next;
  }
};

template<typename I, typename Container, typename R>
SelectErase<Container,R> select_erase(R (Container::*)(I)) {
  return SelectErase<Container,R>();
}
} // namespace detail

template<typename Container, typename Iterator>
Iterator erase(Container& container, Iterator where) {
  return detail::select_erase<Iterator>(&Container::erase).erase(container, where);
}

这需要:

  1. c.erase返回下一个项目的迭代器。这就是vector,deque和list的工作方式。
  2. c.erase返回void并且不会使下一个迭代器无效。这就是map,set和(non-stdlib)hash_map的工作方式。

答案 2 :(得分:-4)

在游行中讨厌下雨,但我不认为你的建议是安全的。

i ++是后增量运算符,这意味着在调用erase之后i递增。但擦除会使指向被擦除元素的所有迭代器无效。因此,当i增加时,它不再有效。

如果你很幸运,它可能会偶然正常工作,直到有一天它不再存在。

据我所知,除此之外没有办法解决这个问题:

// tmp and i are both iterators
tmp = i;
++i;
hash_map.erase(tmp);