从标准角度看std :: list前哨节点

sva*_*vak 5 c++ iterator stl language-lawyer

代码示例:


    list<int> mylist{10, 20, 30, 40};
    auto p = mylist.end();
    while (true)
    {
        p++;
        if (p == mylist.end()) // skip sentinel
            continue;
        cout << *p << endl;
    }
Run Code Online (Sandbox Code Playgroud)

我想知道,从标准(C ++ 17,n4810)角度来看,这段代码多少合法?我在寻找与上述示例相关的双向迭代器要求,但是没有运气。

我的问题是:

是否可以通过end(),是实现细节还是标准要求?

P.W*_*P.W 4

引用自网上提供的最新草案。 [iterator.requirements.general]/7

正如指向数组的常规指针保证有一个指针值指向数组的最后一个元素,因此对于任何迭代器类型,都存在一个指向相应序列的最后一个元素的迭代器值。这些值称为过期值。i定义了表达式的迭代器的值*i称为可解引用。该库从不假设过期值是可取消引用的。

我相信这不仅适用于end()之后的事情。请注意,该标准没有明确规定end()永远不应取消引用。

Cpp17Iterator requirements table指出对于表达式*r,r应该是可取消引用的:

在此输入图像描述

尾后迭代器被认为是不可递增的迭代器,并且递增它(正如您在循环开始时所做的那样while)会导致未定义的行为。

使用时也可能会发生类似您尝试做的事情std::advance

Nicolai Josuttis 所著的《C++ 标准库:教程和参考》一书中有这样的引用:

请注意,advance()不会检查它是否跨越end()序列(它无法检查,因为迭代器通常不知道它们操作的容器)。因此,调用此函数可能会导致未定义的行为,因为++未定义序列末尾的调用运算符。