假设我有一个 hash_map 和一个类似的代码
// i is an iterator
i = hash_map.erase(i)
但是 GCC 的 STL 不会在擦除时返回迭代器,而是一个 void。现在是这样的代码
hash_map.erase(i++)
安全(即不会使迭代器无效或做任何其他意外或不愉快的事情)?请注意这是一个 hash_map。
是的,这是安全的,因为在i
删除当前值之前, 的值将被设置为下一个值。
根据关于散列容器失效的 SGI 文档,对于未擦除的元素,甚至调整大小都不会发生(没有关于插入是否会导致调整大小的消息,所以要小心,我承认这是一种可能性)---但是在后一种情况,迭代顺序将被改变。但这不适用于这里,除非您在遍历或其他情况下不遗余力地调整容器的大小。:-)
您可以封装擦除为您使用的所有容器提供相同的接口:
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);
}
这需要:
讨厌在游行中下雨,但我认为你的提议并不安全。
i++ 是后自增运算符,这意味着 i 在调用擦除后自增。但是擦除使所有指向被擦除元素的迭代器无效。因此,当 i 增加时,它不再有效。
如果你幸运的话,它可能会意外地正常工作,直到有一天它不再起作用。
据我所知,没有办法解决这个问题,但类似:
// tmp and i are both iterators
tmp = i;
++i;
hash_map.erase(tmp);