6

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

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

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

IE

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

4 回答 4

7

你读错了。该表达--c.end()从未被授权。如果迭代器至少不是双向的,实际上它是明确禁止的,并且需要编译器错误。如果集合为空,则为未定义行为。在所有其他情况下,如果它编译,它将工作 ,但不能保证它会编译。它无法与许多早期实现一起编译std::vector,例如,迭代器只是指向指针的 typedef。(事实上​​,我正式认为它在所有情况下都是未定义的行为,因为您违反了对模板化实现的约束。但是,在实践中,您会得到我刚才描述的内容。)

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

编辑(附加信息):

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

prev( c.end() );

当然,迭代器是双向的或更好的,容器不为空的约束仍然成立。

于 2012-08-21T14:38:44.753 回答
7

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

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

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

如果您查看其中一些所做的事情,您应该会看到该算法通常会减少范围结束迭代器并取消引用结果。

正如 James 所说,对于容器,该函数按 valueend()返回一个迭代器。没有一般要求对于应该是格式正确的表达式的迭代器 when是类型的右值。例如,指针是双向迭代器,声明为的函数按值返回指针,并且不是格式良好的表达式。碰巧的是,对于您在实现中查看的容器,返回一个已定义为成员函数的类类型,因此代码可以编译。它也可以工作,因为容器不是空的。--xxint *foo();--foo()end()operator--

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

auto last = --c.end();

对比

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

前者减少一个右值,而后者减少一个左值。

于 2012-08-21T14:59:43.733 回答
1

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

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

于 2012-08-21T14:29:23.320 回答
0

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

于 2012-08-21T14:27:41.327 回答