正在递减离端迭代器

Decrementing an off the end iterator

本文关键字:迭代器      更新时间:2023-10-16

我今天读到关于支持双向迭代的容器如何使用这段代码:

Collection c(10, 10);
auto last = --c.end();
*last;

这让我思考,当向STL中定义了--end的算法提交一对双向迭代器[beg,end)时,是否需要?如果是,结果是否应该是可引用的?

void algo(T beg, T end){
    //...
    auto iter = --end;
    //...
    *iter;
} 

如果算法需要由双向迭代器firstlast定义的范围,则--last需要在与++first相同的条件下有效,即范围不为空。当且仅当first == last

如果该范围不为空,则--last的计算结果为引用该范围中最后一个元素的迭代器,因此*--last确实也需要有效。

也就是说,没有那么多标准算法专门需要双向迭代器(并且不需要随机访问)。prevcopy_backwardmove_backwardreversereverse_copystable_partitioninplace_merge[prev|next]_permutation

如果你看看其中一些算法的作用,你应该会发现该算法通常会减少范围结束迭代器并取消引用结果。

正如James所说,对于容器,函数end()按值返回迭代器。对于迭代器来说,当x是该类型的右值时,--x应该是一个格式良好的表达式,这并不是一个普遍的要求。例如,指针是双向迭代器,声明为int *foo();的函数按值返回指针,而--foo()不是格式良好的表达式。恰好,对于您在实现中看到的容器,end()返回一个类类型,该类类型将operator--定义为成员函数,因此代码进行编译。它也能工作,因为容器不是空的。

请注意,在这方面存在差异

auto last = --c.end();

与。

auto last = c.end();
--last;

前者递减右值,而后者递减左值。

你读错了。表达式--c.end()从未被授权。如果迭代器至少不是双向的,事实上,它是明确的禁止,并且需要编译器错误。如果集合为空,这是未定义的行为。在所有其他情况下,如果它可以编译,但不能保证它会编译。它失败了使用std::vector的许多早期实现进行编译例如,迭代器只是指向指针的typedef。(实际上,我正式地认为,在所有情况下,这都是未定义的行为,因为您违反了对模板化实现的约束。在里面练习,不过,你会得到我刚才描述的。)

可以说,因为它没有保证,一个好的实现将导致它无法系统地编译。由于各种原因,大多数人没有。不要问我为什么,因为让它失败非常简单系统地:只需使迭代器上的operator--免费函数,而不是成员。

编辑(附加信息):

事实上,不需要它可能是CCD_ 26和CCD_。当然我做过的每一个项目都有它们。正确的方式写这是:

prev( c.end() );

当然,迭代器是双向的或更好的是,容器不是空的,仍然可以容纳。

每个算法都会告诉您它需要什么类型的迭代器。当双向迭代器被调用时,它自然需要支持递减。

CCD_ 28是否可能取决于CCD_。

只有需要双向迭代器的算法才需要它。