我今天正在阅读有关支持双向迭代的容器的内容,这段代码是有效的:
Collection c(10, 10);
auto last = --c.end();
*last;
这让我开始思考,是否需要将一对双向迭代器 [beg, end) 提交给 STL 中定义了 --end 的算法?如果是这样,结果应该是可取消引用的吗?
IE
void algo(T beg, T end){
//...
auto iter = --end;
//...
*iter;
}
你读错了。该表达--c.end()
从未被授权。如果迭代器至少不是双向的,实际上它是明确禁止的,并且需要编译器错误。如果集合为空,则为未定义行为。在所有其他情况下,如果它编译,它将工作
,但不能保证它会编译。它无法与许多早期实现一起编译std::vector
,例如,迭代器只是指向指针的 typedef。(事实上,我正式认为它在所有情况下都是未定义的行为,因为您违反了对模板化实现的约束。但是,在实践中,您会得到我刚才描述的内容。)
可以说,因为不能保证,一个好的实现会导致它无法系统地编译。由于各种原因,大多数人不这样做。不要问我为什么,因为让它系统地失败非常简单:只需operator--
将迭代器上的 设为自由函数,而不是成员。
编辑(附加信息):
它不是必需的这一事实可能是C++11背后std::next
的很大一部分动机。std::prev
当然,无论如何,我从事的每个项目都有它们。正确的写法是:
prev( c.end() );
当然,迭代器是双向的或更好的,容器不为空的约束仍然成立。
如果算法需要由双向迭代器定义的范围first
和last
,则--last
需要在相同的条件下有效++first
- 即范围不为空。范围为空当且仅当first == last
。
如果范围不为空,则--last
评估为引用范围中最后一个元素的迭代器,因此*--last
确实也需要有效。
也就是说,并没有那么多标准算法需要专门的双向迭代器(并且不需要随机访问)。prev
, copy_backward
, move_backward
, reverse
, reverse_copy
, stable_partition
, inplace_merge
, [prev|next]_permutation
.
如果您查看其中一些所做的事情,您应该会看到该算法通常会减少范围结束迭代器并取消引用结果。
正如 James 所说,对于容器,该函数按 valueend()
返回一个迭代器。没有一般要求对于应该是格式正确的表达式的迭代器 when是类型的右值。例如,指针是双向迭代器,声明为的函数按值返回指针,并且不是格式良好的表达式。碰巧的是,对于您在实现中查看的容器,返回一个已定义为成员函数的类类型,因此代码可以编译。它也可以工作,因为容器不是空的。--x
x
int *foo();
--foo()
end()
operator--
请注意,在这方面存在差异:
auto last = --c.end();
对比
auto last = c.end();
--last;
前者减少一个右值,而后者减少一个左值。
每个算法都会告诉你它需要什么类型的迭代器。当调用双向迭代器时,它自然需要支持递减。
是否--end
可能取决于是否end == beg
。
只有需要双向迭代器的算法才需要它。