【问题标题】:C++ Why does these codes work?C++ 为什么这些代码有效?
【发布时间】:2016-05-08 13:27:32
【问题描述】:

为什么删除后还能打印'e'?

set <int> s;
for (auto &e : s){
    s.erase(e);
    cout << e;
}

这里也一样,

list <int> l;
l.push_back(1);
l.push_back(2);
auto it = l.begin();

为什么会这样

l.erase(it++);
cout << *it;

这不是吗?

l.erase(it);
it++;
cout << *it;

【问题讨论】:

  • 未定义的行为。

标签: c++ pointers stl


【解决方案1】:

在这两种情况下,您都有未定义的行为。第一个e 是对已销毁对象的引用(悬空引用)。对该引用的任何访问都是未定义的行为。它可能会崩溃、打印随机数或格式化您的硬盘。在这种情况下,它似乎打印了您首先想到的数字。

在列表的情况下,有效的情况是:

auto it2 = it;
it++;
l.erase(it2);
cout << *it;

在第二种情况下:

l.erase(it);
// it is no longer valid at this point.  You cannot use it.
it++;  // Undefined behaviour.
cout << *it; // Anything can happen

【讨论】:

  • 基于范围的循环也有与最终情况相同的错误(因为基于范围的循环是根据循环递增迭代器来定义的)。
【解决方案2】:

“工作”。

它只是似乎起作用,纯属偶然。

您的程序实际上有一个致命的错误。

编译器在一般情况下不会为您检测到此错误(因为它们不能),因此您的代码仍然可以编译。在一般情况下,C++ 运行时不会为您进行内存边界检查(因为您不会为不使用的东西付费,这将是我们强加给我们的一项昂贵的功能),所以您的代码仍在运行。

但是你写了一个无效的程序。

【讨论】:

    【解决方案3】:

    在列表的情况下,当您传递参数 it++ 时,迭代器在分配给擦除函数后已递增,因此迭代器仍然有效并指向集合中的下一个元素。

    在第二种情况下,迭代器无效,因为它在增量之前已被擦除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-02
      • 2012-11-04
      • 1970-01-01
      相关资源
      最近更新 更多