4

假设我有一个 hash_map 和一个类似的代码

// i is an iterator
i = hash_map.erase(i)

但是 GCC 的 STL 不会在擦除时返回迭代器,而是一个 void。现在是这样的代码

hash_map.erase(i++)

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

4

3 回答 3

6

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

根据关于散列容器失效的 SGI 文档,对于未擦除的元素,甚至调整大小都不会发生(没有关于插入是否会导致调整大小的消息,所以要小心,我承认这是一种可能性)---但是在后一种情况,迭代顺序将被改变。但这不适用于这里,除非您在遍历或其他情况下不遗余力地调整容器的大小。:-)

于 2008-10-20T09:38:42.227 回答
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 返回下一项的迭代器。这就是向量、双端队列和列表的工作方式。
  2. c.erase 返回 void 并且不会使下一个迭代器无效。这就是 map、set 和(非标准库)hash_map 的工作方式。
于 2010-02-20T21:04:27.117 回答
-4

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

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

如果你幸运的话,它可能会意外地正常工作,直到有一天它不再起作用。

据我所知,没有办法解决这个问题,但类似:

// tmp and i are both iterators
tmp = i;
++i;
hash_map.erase(tmp);
于 2008-10-21T01:30:53.897 回答