【问题标题】:Does incrementing a mutable input iterator invalidate old iterator values?增加可变输入迭代器是否会使旧的迭代器值无效?
【发布时间】:2012-08-09 08:53:30
【问题描述】:

进一步满足输出迭代器要求的迭代器称为可变迭代器。不可变迭代器被称为常量迭代器。 [24.2.1:4]

这表明您可以有一个可变的输入迭代器,它同时满足输入和输出迭代器的要求。

在增加输入迭代器后,其旧值的副本不需要可取消引用 [24.2.3]。但是,标准对输出迭代器的规定并不相同。事实上,后缀增量的操作语义被给出为{ X tmp = r; ++r; return tmp; },这表明输出迭代器可能不会使旧迭代器值无效(副本)。

那么,增加可变输入迭代器是否会使旧的迭代器副本失效?

如果是这样,您将如何支持带有(例如)代理对象的 X a(r++); *a = tX::reference p(*r++); p = t 之类的代码?

如果不是,那为什么boost::iterator 声称它需要一个代理对象? (链接是代码;向下滚动以阅读 structs writable_postfix_increment_proxypostfix_increment_result 上的 cmets)。也就是说,如果您可以返回旧迭代器值的(可取消引用)副本,为什么需要将此副本包装在代理中?

【问题讨论】:

  • 哦,我多么讨厌这些语言律师问题。还不如争论有多少天使在针头上跳舞。
  • @MarkRansom 是的,我确实讨厌人们试图理解他们使用的语言。该死的……我需要在 this 评论中告诉全世界我对他们的仇恨(为了记录,迭代器类别在 C++ 中很重要。了解它们中的每一个可以做的非常有用)
  • @MarkRansom:我的问题对我来说很重要,因为肯定的答案意味着我必须向我的类添加另一个代理对象来处理可变输入迭代器,就像 Boost 一样。下面的共识表明不存在可变输入迭代器之类的东西(尽管 24.2.1:4 中有注释)。这反过来表明 Boost 在处理“可变输入迭代器”时是不正确的 --- 如果即使 Boost 开发人员也误解了标准的这一方面,这难道不是一个应该解决的问题吗?
  • @nknight,我在深夜写了我的评论,它肯定比它需要的更讽刺。我写这篇文章是因为无法想象一个答案很重要的情况,即使我知道这个问题更有可能是我的想象力而不是问题。感谢您提供更多背景信息,请原谅我如此粗鲁。

标签: c++ iterator


【解决方案1】:

如果在下一节中找到解释,[24.2.5] 前向迭代器,其中说明了它们与输入和输出迭代器的区别:

X 类型的两个可解引用迭代器 ab 提供 多次通过保证,如果:

a == b 暗示 ++a == ++b
X 是指针类型或表达式(void)++X(a), *a 等价于表达式*a

[ 注意:a == b 隐含 ++a == ++b 的要求(对于输入和输出迭代器不成立)以及通过可变迭代器(适用于输出迭代器)消除对赋值数量的限制允许使用带有前向迭代器的多通道单向算法。 ——尾注]

不幸的是,标准必须作为一个整体来阅读,而且解释并不总是如您所期望的那样。

【讨论】:

  • 我还是很困惑,抱歉。您是说对于不使旧值无效的可变输入迭代器,它必须满足多遍保证?感谢您的回答!
  • 不,我是说前向迭代器需要做你想做的事,输入迭代器不是。该标准没有任何中间内容。即使您拥有前向迭代器的一些 属性,它仍然是输入或输出迭代器,直到满足所有 要求。考虑一个输入迭代器可以连接到一个键盘。即使您保存了一份副本,您也无法备份并让我重新输入文本。与输出迭代器类似,它可以直接进入打印机。
  • 哦!我将保留那个键盘/打印机类比以供将来重用:D
  • "标准中间没有任何东西" -- 澄清一下,您是说标准使得输入迭代器不可能 (这也不是前向迭代器)来额外满足输出迭代器的要求?如果这是声明,那么与其讨论多遍保证,我们是否可以说如果旧的迭代器可以失效,就不可能满足输出迭代器的后缀增量的操作语义?这个问题与合并输入和输出迭代器的需求有关;在发生冲突的情况下,哪些要求胜出?
  • @nknight 输入迭代器和前向迭代器之间的标准中没有任何内容。您当然可以编写适合您的东西,但它不符合标准的迭代器类别。已经有人提议进行更细粒度的分类,并将遍历与访问对象的方式分开。但这并没有影响标准。
【解决方案2】:

输入和输出迭代器基本上被设计为允许单次遍历:描述每个元素只能被访问一次的序列。

流就是一个很好的例子。如果您从标准输入或套接字读取,或写入文件,则只有流的当前位置。当您递增一个迭代器时,所有其他指向相同底层序列的迭代器都将失效。

前向迭代器允许多次遍历,这是您需要的额外保证:它们确保您可以复制您的迭代器,增加原始迭代器,并且副本将仍然指向旧​​位置,因此您可以从那里迭代。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-04-22
  • 2012-06-16
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
相关资源
最近更新 更多