【问题标题】:Iterator to one past the last element in list迭代器到列表中最后一个元素的过去
【发布时间】:2020-08-16 12:16:19
【问题描述】:

我正在努力实施我自己的清单。我看到 std::list::end() 将迭代器返回到列表容器中最后一个元素的位置。由于列表元素存储在不连续的内存位置,我想知道如何估计这个过去元素的位置。

std::list<int> ls;
ls.push_back(1);
ls.push_back(2);
std::list<int>::iterator it = ls.end();
std::cout << &(*it) << std::endl << &(*++it) << std::endl << &(*++it) << std::endl;

正如上面的代码所示,我什至可以递增迭代器以指向下一个元素。如何知道下一个元素将存储在哪个位置(在内存中)?

【问题讨论】:

  • 你没有。对于列表迭代器,结束迭代器 always 指向列表末尾之后的位置。向列表末尾添加更多值,完全相同的迭代器仍然指向列表末尾之后的一个std::list 的“列表末尾之后的一位”迭代器永远指向列表末尾之后的一位,并且将永远继续这样做,无论列表是空的,还是吃掉你所有的内存。跨度>
  • 这不是我的问题。问题是列表如何知道在将下一个元素添加到列表之前将其存储在内存中的哪个位置?
  • 我回答了。它没有。如果您使用结束迭代器向列表添加新值,它将转到分配给它的任何内存。并且列表迭代器仍将指向列表末尾的“过去”。提示:“列表末尾的一个”不是,我重复一遍, 表示特定的内存位置。这是一个“概念价值”。一些神奇而神秘的值,总是被列表方法解释为列表中最后一个值之后的意思。
  • 代码只显示未定义行为之神在嘲笑你。取消引用或递增end() 迭代器是UB,您的程序无效。
  • 关于你自己的实现,我可以看到两种可能性(可能还有更多):你可以让end() 成为nullptr,然后按照next 指针,你最终会到达@987654327 @你知道它已经停止了。或者你可以有一个表示“结束”的哨兵对象,你可以识别它(也许它可以有 next 指向 this 或者你可以只将指向哨兵的指针存储在列表对象或迭代器本身中)。

标签: c++


【解决方案1】:

如何知道下一个元素将存储在哪个位置(在内存中)?

事实并非如此。此外,使用该内存地址作为(部分)过去的迭代器是不正确的。

不是:
迭代器(不一定)不是指针。不需要迭代器来存储内存地址。需要的是解引用运算符能够计算内存地址(以引用的形式返回)。 好消息,大家! 将取消引用运算符应用于过去的迭代器是未定义的行为。所以即使这个减少的要求也不适用于过去的迭代器。如果您要存储地址,请继续存储您想要的任何内容。 (只要保持一致,因为两个过去的迭代器必须比较相等。)

如果您的迭代器确实存储了一个指针(这可能很常见),一个简单的方法是存储您在列表中最后一个节点的next 字段中放置的任何内容。这通常是 nullptr 或指向列表哨兵节点的指针。

不正确:
将元素添加到列表时,std::list 不会使迭代器无效。 这包括过去的迭代器。(参见cppreference.com。)如果你的过去的迭代器指向下一个元素将被存储的位置,它会通过添加该元素而失效到列表中。因此,您将无法满足 std::list 的迭代器失效要求。因此,不仅不可能将该地址存储在过去的迭代器中,而且是不允许的。

【讨论】:

    猜你喜欢
    • 2021-03-05
    • 1970-01-01
    • 2013-02-20
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 2019-01-28
    相关资源
    最近更新 更多