C++ 什么是非void STL擦除的安全等价物?

C++ 什么是非void STL擦除的安全等价物?,c++,stl,iterator,hashmap,C++,Stl,Iterator,Hashmap,假设我有一个hash_映射和如下代码 // i is an iterator i = hash_map.erase(i) hash_map.erase(i++) 但GCC的STL并没有以擦除的形式返回迭代器,而是一个空值。现在代码是什么样子的 // i is an iterator i = hash_map.erase(i) hash_map.erase(i++) 安全(即不会使迭代器无效或做任何其他意外或不愉快的事情)?请注意,这是一个哈希映射。是的,这是安全的,因为在删除当前值之前,

假设我有一个hash_映射和如下代码

// i is an iterator
i = hash_map.erase(i)
hash_map.erase(i++)
但GCC的STL并没有以擦除的形式返回迭代器,而是一个空值。现在代码是什么样子的

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

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

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


根据这一点,对于未擦除的元素,甚至对于大小调整,都不会发生无效(没有关于插入是否会导致大小调整的消息,所以要小心,我承认这是一种可能性)——但在后一种情况下,迭代顺序将被更改。但这不适用于此处,除非您在遍历或其他过程中特意调整容器的大小。:-)

我不想在游行上下雨,但我认为你的提议不安全

i++是后增量运算符,这意味着在调用擦除后i将递增。但是erase会使指向被擦除元素的所有迭代器失效。所以当我递增时,它就不再有效了

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

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

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

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

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);
}
名称空间详细信息{
模板
结构选择擦除{
//默认情况下,假设返回下一个迭代器
模板
迭代器擦除(容器&c、迭代器where){
返回c.erase(其中);
}
};
//专门处理返回类型void
模板
结构选择擦除{
模板
迭代器擦除(容器&c、迭代器where){
迭代器next(其中);
++其次;
c、 删除(何处);
下一步返回;
}
};
模板
选择擦除选择擦除(R(容器::*)(I)){
返回SelectErase();
}
}//名称空间详细信息
模板
迭代器擦除(容器&容器,迭代器,其中){
返回详细信息::选择擦除(&容器::擦除)。擦除(容器,其中);
}
这需要:

  • c、 擦除返回下一项的迭代器。这就是vector、deque和list的工作方式
  • c、 擦除返回void,不会使下一个迭代器无效。这就是map、set和(非stdlib)散列映射的工作方式

  • 你能指出你在哪里读到的吗?对于ISO C++中定义的关联容器来说,这是正确的,但是我从来没有在SGI文档中读过类似的东西。我确实假设,对于该站点,除非另有特别说明,否则操作不会导致无效。请参阅(例如)其中提到的所有失效案例。(我选择vector是因为它是一种失效案例(似乎)比其他任何类型都多的数据类型。)根据标准,it++和it--(其中它是迭代器)相当于创建一个等于它的临时值,递减迭代器,返回临时值。是的,但是编译器可以在调用erase之前或之后自由调用(i++),因此如果编译器决定在erase之后调用(i++),那么i是无效的。Rodyland,你对此有什么引用吗?我从来没有听说过。我做了进一步的阅读,似乎我弄错了-编译器在调用erase之前被迫求值(I++),所以它是安全的。尽管如此,我还是不喜欢它。我同意这是一个不太安全的项目,但在这种情况下定义了增量运算符的使用。关于同一主题的更多信息: