减少一个结束迭代器

时间:2012-08-21 14:26:07

标签: c++ stl iterator

我今天正在阅读有关支持双向迭代的容器的方法,这段代码是有效的:

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

这让我想到,是否需要将一对双向迭代器[求,结束]提交给STL中定义了--end的算法?如果是这样,结果是否可以解除引用?

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

4 个答案:

答案 0 :(得分:7)

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

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

编辑(附加信息):

不需要的事实可能是其中的很大一部分 C ++ 11中std::nextstd::prev背后的动机。当然, 无论如何,我工作的每个项目都有它们。正确的方法 写这个是:

prev( c.end() );

当然,迭代器是双向的约束 更好,并且容器不是空的,仍然保持。

答案 1 :(得分:7)

如果算法需要双向迭代器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();

VS

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

前者递减一个rvalue,而后者递减一个左值。

答案 2 :(得分:1)

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

--end是否可行取决于end == beg

答案 3 :(得分:0)

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