【问题标题】:How is *it++ valid for output iterators?*it++ 如何对输出迭代器有效?
【发布时间】:2011-04-29 10:15:45
【问题描述】:

在示例代码中,我经常看到诸如*it++ 之类的代码用于输出迭代器。表达式*it++ 复制it,递增it,然后返回最终取消引用的副本。据我了解,制作输出迭代器的副本会使源无效。但是在创建副本之后执行的it 的增量是非法的,对吧?我对输出迭代器的理解有缺陷吗?

【问题讨论】:

  • 为什么复制迭代器(输出或其他)会使它失效?当我们说诸如vector<int>::iterator it(container.begin());之类的话时,我们不是经常这样做吗?
  • @Adrian:例如,SGI documentation 说:“在任何时候都应该只有一个输出迭代器的一个活动副本。即:在创建和使用一个副本 x 之后输出迭代器 y,不应再使用原来的输出迭代器 y。”不过,我不确定在这种情况下“使用”输出迭代器是什么意思。取消引用?递增?
  • 我看到了 out_iterator a(b); 之后的暗示,b 可能像你说的那样在 SGI 文档中无效,但 C++03 中没有任何暗示。但由于 SGI 页面和 C++03 都明确表示表达式 *it++ = value 必须有效,因此该要求覆盖了有关该使用的任何其他问题。

标签: c++ stl iterator post-increment


【解决方案1】:

标准要求*r++ = t 可用于输出迭代器 (24.1.2)。如果它不起作用,则它不是标准定义的输出迭代器。

由迭代器实现来确保此类语句在后台正常工作。

您不应该保留输出迭代器的多个副本的原因是它具有单遍语义。迭代器只能在每个值处取消引用一次(即它必须在每次取消引用操作之间递增)。一旦迭代器被取消引用,它的副本就不能被取消引用。

这就是*r++ = t 起作用的原因。复制原始迭代器,取消引用原始迭代器并增加副本。原来的迭代器将永远不会被再次使用,并且副本不再引用相同的值。

【讨论】:

  • @Seth No. 原题指定输出迭代器。
  • @Seth:不,*r++ = t 是您使用输出迭代器的方式。反过来甚至不需要编译。
  • +1 绝对比我的回答更正确,并且很好地解释了正在发生的事情。
【解决方案2】:

表达式*it++ not(必须)复制它,not 增加它,等等。 这个表达式只是为了方便而有效,因为它遵循通常的语义。只有operator= 完成实际工作。例如,在 ostream_iteratoroperator*operator++operator++(int) 的 g++ 实现中,只做一个的事情:return *this(换句话说,什么都不做!)。例如,我们可以这样写:

it = 1;
it = 2;
*it = 3;
++it = 4;

代替:*it++ = 1; *it++ = 2; *it++ = 3; *it++ = 4;

【讨论】:

  • 这个答案让我惊叹不已,因此我选择它作为正确答案。
  • 您可能应该明确指出,第一个示例仅适用于您知道实现,而第二个示例是使用输出迭代器的正确方法。
  • @Dingo:如果我正确理解标准,它不依赖于实现,而是为ostream_iterator 定义良好。所以在一般情况下,不能要求*it++ 进行复制等。
  • 该标准在关于 osteram_iterator 的部分中说:“它的唯一用途是在while (first != last) *result++ = *first++; 等情况下用作输出迭代器”事实上,您的示例it = 2;*it = 3; 和@987654335 @,工作是因为实现,而不是因为标准规定。
  • @Dingo:好吧,我不知道你引用的那句话的意思是“这是唯一可能的用途,你不能使用*resultresult++...当我阅读“ostream_iterator operation”部分(24.5.2.2),我将“Effects”规范的缺失解释为:“什么都不做”。
【解决方案3】:

查看您的评论,似乎大部分混淆都来自 SGI 文档,我想说这在这一点上有点误导。

复制输出迭代器不会使复制的迭代器无效。真正的限制非常简单:您应该只取消引用输出迭代器的给定值一次。但是,一次拥有两个副本是可以的,只要您在它们具有相同值时只取消引用其中一次。在这种情况下,您要取消引用一个,然后丢弃它的值,并增加另一个,但只有在增量发生后才取消引用它,这一切都很好。

【讨论】:

    【解决方案4】:

    输出迭代器只是不像普通迭代器那样工作,并且它们的接口被指定,以便它们可以在类似指针的表达式 (*it++ = x) 中使用并获得有用的结果。

    通常,operator*()operator++()operator++(int) 都返回 *this 作为引用,输出迭代器有一个神奇的 operator= 执行预期的输出操作。因为您无法从输出迭代器中读取,所以 operator*() 等不能像其他迭代器一样工作这一事实并不重要。

    【讨论】:

      【解决方案5】:

      迭代器不只是一个指针吗?递增,然后取消引用它只是移动到下一个元素。

      【讨论】:

      • 它们可以被取消引用,就像指针一样,这可能会让你感到困惑,但是不,它们不仅是指针,它们还包含指向元素的指针等等。这是一个迭代器的示例实现:accu-usa.org/Listings/2000-04-Listing01.html
      • 啊,我明白了。我从来没有看到过迭代器的意义,我也从来不需要它们。
      猜你喜欢
      • 2010-11-07
      • 1970-01-01
      • 1970-01-01
      • 2012-01-21
      • 2019-06-14
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多