【问题标题】:Does unordered_set::erase(pos) preserve the order of elements?unordered_set::erase(pos) 是否保留元素的顺序?
【发布时间】:2016-11-13 17:14:55
【问题描述】:

我在 C++14 的标准中读到,使用 erase(iterator pos)unordered_set 时元素的顺序被保留。

我用 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

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

发生了什么事?

【问题讨论】:

  • 该标准有超过 1000 页的文本。说您在标准中阅读它是没有用的。您在标准的什么地方读到了这个?

标签: c++ stl std erase unordered-set


【解决方案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;
    }
}

【讨论】:

  • 或者你可以只使用'erase'的返回值。
  • @JesperJuhl 仅从 C++11 开始。
  • 现在已经 5 岁了,应该是最低标准(不,从头开始,C++ 14 应该是) - 但“是”当然..
  • 在某些地方(比如我现在的工作)C++03 是默认的。所以我下意识地在我的一些答案中使用它作为默认标准:) 显然这个问题属于 C++1z 的土地,所以你描述的擦除形式可能更可取。
猜你喜欢
  • 2010-11-29
  • 2011-11-05
  • 1970-01-01
  • 2016-07-14
  • 2011-04-12
  • 1970-01-01
相关资源
最近更新 更多