比较两个end()迭代器

3
list<int> foo;
list<int> foo2;
list<int>::iterator foo_end = foo.end();
list<int>::iterator foo2_end = foo2.end();

for (list<int>::iterator it = foo.begin(); it != foo2_end; ++foo) <- notice != comparison here
{
   ...

这个允许吗?它能正常工作吗。

我倾向于认为这取决于实现,有人知道标准是否对此有规定吗?

3个回答

7

有一个缺陷报告与此相关 (LWG defect 446)。 缺陷报告询问是否可以比较引用不同容器元素的迭代器。

缺陷报告中的注释解释说,这显然是有意未定义的,但没有明确说明它是未定义的。

建议的解决方案是向标准添加以下内容,明确说明它是未定义的:

直接或间接评估具有两个迭代器值作为参数的任何比较函数或二进制运算符的结果,在这些值是从不是一个公共范围的两个范围 r1 和 r2(包括其过去的最大值)获得的子范围时是未定义的,除非另有明确说明。

编辑:该语言未包含在 C++0x FCD 中。实际上,此问题通过 N3066 的更改得到了解决;具体而言,添加了以下内容 (§24.2.5/2):

== 对于前向迭代器的定义域是相同基础序列上的迭代器。


2

可以的(即会编译通过)。
会正常工作。

foo2_end 指向 foo2 的末尾,而不是 foo 的末尾,因此您的迭代器将从 foo 的开头开始,并在到达 foo2 的末尾时结束,这永远不会发生,因为您正在迭代 foo。一旦 it 超过了 foo 的末尾,您将收到一个段错误。

注意:我假设您想写 ++it,而不是 ++foo


1

它会编译通过,但会导致段错误。迭代器是对象特定的,比较来自不同对象的两个迭代器将始终产生不等式。因此,it != foo2_end 表达式将始终评估为 true,并且当 it 到达 foo.end() 并尝试对其进行解引用时,您的程序将崩溃。


这取决于迭代器的实现。一个微不足道且不是很好的列表迭代器实现可能是一个指向节点的指针,其中null标识结束(这是一种常见的习惯用法)[也许某些操作需要指向列表的指针],相等性被定义为所引用节点地址的直接比较。标准中没有任何东西会使该实现不符合规范。 - David Rodríguez - dribeas
可以理解,不过我认为商用级别的编译器会更聪明一些。毕竟,使接口易于正确使用且难以错误使用是一个好的共同目标。 :) - Artem Sokolov
@DavidRodríguez-dribeas:“列表迭代器的实现可以是指向节点的指针,其中null表示超出末尾(这是一种常见的习惯用法)”。你能引用一个这样的破损std::list实现吗? - curiousguy
@Artem "商业级编译器应该对此更加聪明。" 确实,在这种情况下,商业级编译器应该进行断言。 - curiousguy
@curiousguy:除了使用一个持有指向第一个和最后一个节点的指针(闭环)的 sentry 对象使实现更简单之外,没有任何阻止使用 std::list 的相同方法。重点是,比较来自不同容器的迭代器是未定义行为,但这并不意味着它会导致 segfault。 - David Rodríguez - dribeas
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接