【问题标题】:Input iterator can be read repeatedly while Output Iterator can only be written once?输入迭代器可以重复读取,而输出迭代器只能写入一次?
【发布时间】:2019-01-31 19:04:51
【问题描述】:

我正在阅读 Bjarne Stroustrup 的 The C++ Programming Language 第 4 版。在迭代器章节(第 31.1.2 章)中,它说:

输入迭代器:我们可以使用 ++ 向前迭代并使用 * 读取每个元素(重复)。

输出迭代器:我们可以使用 ++ 向前迭代并使用 * 编写一个元素仅一次

我对输入迭代器是否只能读取一次或重复进行了多次搜索,例如: http://www.cplusplus.com/reference/iterator/InputIterator/ https://www.geeksforgeeks.org/input-iterators-in-cpp/

并且大多数建议输入迭代器只能读取一次。但是为什么作者反复说输入迭代器呢?它是否正确?如果是这样,为什么输入迭代器可以重复读取,而输出迭代器只能写入一次。我一直认为输入和输出迭代器是完全相反的。

谢谢大家!

【问题讨论】:

    标签: c++ c++11 iterator input-iterator


    【解决方案1】:

    这本书是正确的;而矛盾的来源不是。似乎没有规则禁止通过输入迭代器间接读取对象多次。

    其他来源可能会被另一个类似的限制混淆,即一旦输入迭代器增加,前一个迭代器的所有副本都将失效,因此可能不再被间接引用。此限制由输出迭代器共享。举例:

    value = *inputIt;
    value = *inputIt; // OK
    copyIt = inputIt;
    ++inputIt;
    value = *copyIt;  // Not OK
    

    这本书也是正确的,输出迭代器确实有限制:

     *outputIt = value;
      ++outputIt;
     *outputIt = value; // OK
     *outputIt = value; // Not OK
    

    我一直认为输入和输出迭代器是完全相反的。

    许多输出迭代器也是输入迭代器,因此“相反”并不是非常具有描述性。它们是部分重叠的需求集。一个迭代器可以同时满足这两组要求。

    如果我们有 *outputIt = 1;然后 *outputIt = 2;我们不是只分配给同一个 *outputit 两次吗?

    是的;这就是输出迭代器不需要支持的东西。

    例如,考虑一个通过 Internet 发送数据包的输出迭代器。您已经编写了一个数据包,它已被发送到互联网并被其他机器接收。您不能及时返回并确定发送的数据包是不同的。您必须转到下一个数据包并发送它。

    【讨论】:

    • 感谢您的回答。输出迭代器怎么样。例如写 *outputIt = value;两次像你的例子不OK/不会编译?
    • @user9607441 *outputIt = value; *outputIt = value; 不行。它可以编译,因为它的格式很好,但不需要很好地定义行为(可以,取决于迭代器的定义方式)。
    • @user9607441 重要的是要理解,在 c++ 中,有些东西可以同时编译,但不能同时运行。
    • 谢谢大家...我仍然对为什么第二个 *outputIt = value; 感到困惑不行吗?如果我们有 *outputIt = 1;然后 *outputIt = 2;我们不是只是分配给同一个 *outputit 两次吗?是什么阻止我们这样做,这会导致什么样的“未定义行为”?
    • @user9607441 我添加了一个例子来描述为什么它不正常。
    【解决方案2】:

    Bjarne 的引用是正确的。如果您有输入迭代器,您可以根据需要多次执行*iterator。如果你有一个输出迭代器,你只能做一次*iterator

    它们的共同点是它们只能用于单通道算法。一旦你增加了一个输入或输出迭代器,那么一个到前一个位置的迭代器就不再需要是可解引用的了

    这意味着在

    while (iterator != end)
    {
        if (*iterator == some_value)
            something = *iterator;
        ++iterator;
    }
    

    iterator 必须是输入迭代器,因为我们每次迭代都会取消引用它两次。另一方面

    while (iterator != end)
    {
        something = *iterator;
        ++iterator;
    }
    

    适用于输入和输出迭代器,因为我们只做一次解引用。

    【讨论】:

    • 感谢您的回答!但是为什么输出迭代器只能取消引用一次,而输入迭代器可以在++之前多次取消引用而不会导致任何“未定义的行为”
    • @user9607441 这正是标准所允许的。实现可以允许多次取消引用输出迭代器,但标准不会强制实现。为什么我不确定,但它可能与写入输出流有关,他们只希望每个元素获得一个值。
    • 谢谢@NathanOliver!我想我现在明白了。所以标准明确规定输出迭代器只能读取一次,但对输入迭代器没有这个限制?
    • @user9607441 是的。该标准规定您只能安全地取消引用输出迭代器一次。它没有对输入迭代器提出警告,因此您可以根据需要多次取消引用。
    【解决方案3】:

    您可以根据需要多次读取输入迭代器。这来自“(void)*a, *a 等同于*a”[input.iterators] 的要求,见表。

    您只能通过输出迭代器写入一次。对于*r = o,“在此操作之后r 不需要被取消引用”。 [输出.迭代器],见表。增加 r 后,您就有了一个新的迭代器,您可以再次通过它分配一次。

    一旦将这两者组合成一个 forward 迭代器,通过同一个迭代器进行多个赋值的限制就会消失。

    【讨论】:

    • 谢谢@Pete Becker!我刚刚在标准文档中找到了您的参考资料
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 2012-02-10
    • 1970-01-01
    • 2022-11-14
    • 1970-01-01
    相关资源
    最近更新 更多