为啥迭代器指向的数据在从列表中删除后保留

Posted

技术标签:

【中文标题】为啥迭代器指向的数据在从列表中删除后保留【英文标题】:Why is the data pointed by the iterator kept, after deleting it from the list为什么迭代器指向的数据在从列表中删除后保留 【发布时间】:2014-01-14 16:17:11 【问题描述】:

在这个示例程序中,为什么即使列表为空,迭代器所指向的数据的值也保持不变? 是否由于 C++ 中迭代器的实现(即对象的值保存在迭代器中)而必然会发生某些事情,还是因为内存段被声明为可使用的空闲,但还没改?

#include <iostream>
#include <list>
using namespace std;
int main ()

    list<int> mylist;
    list<int>::iterator it = mylist.begin();
    cout << "printing: " << *it << endl;

    mylist.push_back(77);
    mylist.push_back(22);

    // now front equals 77, and back 22

    mylist.front() -= mylist.back();
    it = mylist.begin();
    cout << "printing: " << *it << endl;
    cout << "mylist.front() is now " << mylist.front() << '\n';
    // trying to delete all elements and then see how the iterators are handling it
    it = mylist.begin();
    cout << "printing: " << *it << endl;
    mylist.remove(55);
    cout << "printing: " << *it << endl;
    mylist.remove(22);
    cout << "printing: " << *it << endl;
    cout << "mylist size: " << mylist.size() << endl;
    cout << "mylist.front() is now " << mylist.front() << '\n';
    cout << "printing: " << *it << endl;

    return 0;

这是输出:

printing: 495034304
printing: 55
mylist.front() is now 55
printing: 55
printing: 55
printing: 55
mylist size: 0
mylist.front() is now 38375440
printing: 55

【问题讨论】:

当您的列表为空时访问front 是UB - 可能会发生旧数据仍然存在。否则恶魔可能会从你的鼻子里飞出来。 这只是未定义的行为。迭代器已失效。 @doctorlove:哈哈很好的答案,但我并不怀疑*it 的列表前面,即使从列表中删除它也会打印 55。 "这是因为内存段被声明为空闲,但尚未更改"(并且因为你很幸运没有崩溃你的程序或格式化你的硬盘驱动器通过调用 UB)。 @abiessu:这里就是这样使用的,cplusplus.com/reference/list/list/front,只是示例,但稍作修改。 【参考方案1】:

由于在 C++ 中实现迭代器而必然会发生什么

不,这是未定义的行为。迭代器已失效,无法使用。

是不是因为这块内存被声明为free for used,但还没有改变?

是的,这就是你观察你所观察到的东西的原因。但是内存可以被重新用于其他用途,或者无法访问 - 您不能依赖对未定义行为的任​​何观察。

【讨论】:

【参考方案2】:

迭代器因您的操作而无效,但它可能仍指向具有先前值的内存。无论如何,从列表中删除值后访问它是未定义的行为。

【讨论】:

没有内存泄漏,只是访问不再有效的东西。 @Chris 这无关紧要。你有UB。 可能存在内存泄漏,以及其他令人讨厌的事情。 @Chris - 如果您的意思是“我仍然可以看到数据,那是泄漏吗?”那么不,这不是泄漏,只是内存还没有被重新使用。如果您的意思是“删除这些数据后,我还能继续使用这些数据,而不用担心内存泄漏吗?”那么不,因为无法保证这些数据在被删除后会保留多长时间。 @benjymous:(和 Wojtek)我并不是说将数据视为泄漏。我用 valgrind 检查过,没有检测到泄漏。这不应该导致分段错误,因为在删除(并且可能是空闲的)之后,内存不属于我的程序吗? 可能导致段错误。或者您最终可能会发现内存区域仍然保存旧但仍然有效的数据。这就是你避免UB的原因。它可以在你的机器上工作,但不能在别人的机器上工作。在下面查看您对我的代码的评论。【参考方案3】:
#include <stdio.h>

int main(int argc, char **argv)

    int *p = NULL;

    p = (int*)malloc(sizeof(int));

    *p = 5;

    printf("P: %d\n", *p);

    free(p);

    printf("P: %d\n", *p);

为什么这仍然是一个惊喜?将指针标记为无效与存储它曾经指向的位置无关。

【讨论】:

我已尝试将您的包含添加到段代码中,但无法提交编辑,因为它需要超过 6 个字符。此外,您的代码会打印此 P: 5 P: 0 这就是重点。在我的系统上,我得到 5 和 5。UB 就是 UB。 我用 C 语言编写了我的,以说明指针以及如何将指针融入语言的思维。您可以像使用原始代码一样轻松地使用 new/delete 或迭代器。 我也遇到过P: 5 P: 0,所以很可能被覆盖了。如果您分配 1000 个元素,这将变得不太可能,因此您可能会得到 P: 5 P: 5: coliru.stacked-crooked.com/a/511758849e268b43

以上是关于为啥迭代器指向的数据在从列表中删除后保留的主要内容,如果未能解决你的问题,请参考以下文章

迭代器在添加到添加到列表向量的结构中时会停止指向某个值吗?

为啥在达到容量后在向量中进行插入时,C++ 不处理迭代器?

Java 小程序在从迭代器数组中删除对象时抛出错误

迭代器失效

Python在迭代器中删除列表元素

为啥我在这个迭代器中遇到分段错误?