【问题标题】:c++ set erase function not working properly with iteratorc ++设置擦除功能无法与迭代器一起正常工作
【发布时间】:2021-11-05 06:52:19
【问题描述】:
set<int> s = {1, 2, 3, 4};
auto it = s.begin();
while (it != s.end()) {
    // this correct 
    s.erase(it++);
    
    // this incorrect 
    s.erase(it);
    it++;
}

为什么上面的代码可以运行?

我对代码运行时的顺序的理解是:

  1. 执行擦除函数时,迭代器被删除。
  2. 执行 add 的混乱迭代器,其行为未定义。

但它运行正常,所以我的问题是为什么它可以运行而这些代码有区别?

【问题讨论】:

  • 这在文档中:en.cppreference.com/w/cpp/container/set/erase > 对已擦除元素的引用和迭代器无效。这只是未定义的行为,它可能有效,也可能无效,谁知道呢^^
  • @Someprogrammerdude 为什么?它会按预期工作。
  • @SergeyA 将s.erase(it++) 评估为s.erase(it); it = it + 1;auto temp = it; it = it + 1; s.erase(temp)?定义清楚吗?
  • @Someprogrammerdude 是的,我相信它会像你的第二种情况一样被评估,我很确定它会被很好地定义。后修复增量返回原始操作数的值,因此这将被删除 - 但 it 已经递增。
  • @SergeyA 看来你是对的:“......与任何参数表达式相关的每个值计算和副作用......在每个表达式执行之前排序或被调用函数体中的语句" (en.cppreference.com/w/cpp/language/eval_order)

标签: c++ iterator set


【解决方案1】:

最好的办法是:

it = s.erase(it);

您的后增量代码也可以使用,但透明度较低。回想一下,后增量版本在语义上与以下 sn-p 等效:

temp = it;
++it;
s.erase(temp);

至于您声称“正在运行”的格式错误(第二版)代码,具有未定义行为的代码可能正在“运行”,甚至似乎可以提供预期的结果。这是未定义行为的要点。根据std::set::erasedocumentation,递增已被擦除的迭代器的代码表现出未定义的行为:

对已擦除元素的引用和迭代器无效。其他 引用和迭代器不受影响

【讨论】:

  • 那么这些未定义行为的执行结果被编译器判定了吗?
  • @LYFer 有时编译器会在存在未定义行为的情况下做出某些决定,有时它不会,并且只会生成会以不可预知的结果执行的代码。
猜你喜欢
  • 2013-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多