unordered_set::erase(pos)是否保留元素的顺序?

Does unordered_set::erase(pos) preserve the order of elements?

本文关键字:元素 保留 是否 顺序 pos set erase unordered      更新时间:2023-10-16

我在c++ 14的标准中读到,当使用unordered_seterase(iterator pos)时,元素的顺序是保留的。

我用g++-6.2.0和clang-3.9(在linux上,这个gcc的stdlib)尝试了下面的代码。我认为两者都应该能够在c++ 14规范中处理这个问题:

#include <unordered_set>
#include <iostream>
using std::unordered_set; using std::cout;
// output
template<typename Elem, typename Comp>
std::ostream& operator<<(std::ostream&os, const unordered_set<Elem,Comp>&data) {
    for(auto &e : data) { os << e << ' '; } return os << 'n'; }
int main() {
  unordered_set<int> nums{ 1,2,3,4,5,6,7,8,9,10 };
  cout << nums; // MSVC: 9 1 2 3 4 5 6 7 8 10
  for(auto it = nums.begin(); it!=nums.end(); ++it) {
    if(*it % 2 == 0) {
      nums.erase(it);
    }
  }
  cout << nums; // MSCV: 9 1 3 5 7
}

是的,元素的顺序是任意的。这里msvc++ 19.00有9 1 2 3 4 5 6 7 8 10。并且在擦除所有偶数元素后,剩下的元素仍然是相同的顺序9 1 3 5 7

使用g++和clang++,我得到了一个完全糟糕的输出

10 9 8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1

,这似乎表明元素的顺序在调用之间没有保留,而只是…我不知道。

怎么回事?

我想这个循环是错误的:

for(auto it = nums.begin(); it!=nums.end(); ++it) {
    if(*it % 2 == 0) {
        nums.erase(it);
    }
}

如果执行erase,则it无效且不能递增。可能会导致上述行为。

你应该这样写:

for(auto it = nums.begin(); it!=nums.end();) {
    if(*it % 2 == 0) {
        nums.erase(it++);
    } else {
        ++it;
    }
}