2008-10-20 81 views
3

假设我有一个的hash_map和像什么是非无效STL擦除的安全等价物?

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

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

hash_map.erase(i++) 

安全代码(即不坏的迭代器或是否有任何其他意外或不愉快的事情)?请注意这是一个hash_map。

回答

5

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

根据SGI documentation about hashed containers对于未擦除的元素,甚至对于调整大小(关于是否插入导致调整大小,所以要小心,我承认这是可能性)没有发生无效,但是在后一种情况下,迭代顺序将被改变。但是这并不适用于这里,除非你在遍历期间或者其他方面调整容器的大小。 :-)

+0

你能指出你阅读的地方吗?在ISO C++中定义的关联容器是这样的,但我从来没有在SGI文档中读过类似的东西。 – PierreBdR 2008-10-20 10:31:09

+1

它在我的文章链接到的页面上。我确实假设,除非另有特别说明,否则操作不会导致失效。请参阅http://www.sgi.com/tech/stl/Vector.html(例如)提及所有无效案例的地方。 – 2008-10-20 12:52:56

-4

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

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

如果幸运的话,它可能会正常工作,直到有一天它不再有任何问题。

据我所知是没有办法解决这一点,但这样的:

// tmp and i are both iterators 
tmp = i; 
++i; 
hash_map.erase(tmp); 
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和(non-stdlib)hash_map的工作方式。