我今天正在阅读有关支持双向迭代的容器的方法,这段代码是有效的:
Collection c(10, 10);
auto last = --c.end();
*last;
这让我想到,是否需要将一对双向迭代器[求,结束]提交给STL中定义了--end的算法?如果是这样,结果是否可以解除引用?
即
void algo(T beg, T end){
//...
auto iter = --end;
//...
*iter;
}
答案 0 :(得分:7)
你读错了。表达式--c.end()
永远不会被授权。如果
迭代器至少不是双向的,事实上它是明确的
禁止,并且需要编译器错误。如果收集是空的,
这是未定义的行为。在所有其他情况下,它将如果
它编译,但不能保证它会编译。它失败了
使用std::vector
的许多早期实现进行编译
例如,迭代器只是指针的typedef。 (事实上,
我认为在所有情况下,它都是未定义的行为,因为
你违反了模板化实现的约束。在
但是,练习,你会得到我刚才描述的内容。)
可以说,因为它不能保证,所以会有一个好的实现
它无法系统地编译。由于各种原因,大多数原因没有。
不要问我为什么,因为让它失败是非常简单的
系统地:只需使迭代器上的operator--
免费
功能,而不是成员。
编辑(附加信息):
不需要的事实可能是其中的很大一部分
C ++ 11中std::next
和std::prev
背后的动机。当然,
无论如何,我工作的每个项目都有它们。正确的方法
写这个是:
prev( c.end() );
当然,迭代器是双向的约束 更好,并且容器不是空的,仍然保持。
答案 1 :(得分:7)
如果算法需要双向迭代器first
和last
定义的范围,那么--last
必须在++first
所做的相同条件下有效 - 即范围不是空的。当且仅当first == last
。
如果范围不为空,则--last
求值为迭代器,该迭代器引用范围中的最后一个元素,因此*--last
确实也需要有效。
尽管如此,并没有那么多标准算法需要专门的双向迭代器(并且不需要随机访问)。 prev
,copy_backward
,move_backward
,reverse
,reverse_copy
,stable_partition
,inplace_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)
只需要需要双向迭代器的算法。