为啥在 std::istream_iterator 上使用的 std::find_if 似乎返回最后一个元素?

Posted

技术标签:

【中文标题】为啥在 std::istream_iterator 上使用的 std::find_if 似乎返回最后一个元素?【英文标题】:Why does std::find_if used on std::istream_iterators seem to return the last element?为什么在 std::istream_iterator 上使用的 std::find_if 似乎返回最后一个元素? 【发布时间】:2019-08-23 12:11:03 【问题描述】:

我正在通过 Andrew Koenig 和 Barbara E. Moo 的 Accelerated C++ 学习 C++。我正在尝试了解输入运算符的工作原理以及它们与 STL 算法的关系。

这是让我感到困惑的一段代码:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <cctype>

bool space(char c)

    return std::isspace(c);


int main()

    std::istream_iterator<char> i = std::find_if(
        std::istream_iterator<char>(std::cin),
        std::istream_iterator<char>(),
        space);
    std::cout << *i << std::endl;
    return 0;

代码编译得很好,但是当我在任何输入上运行它时,它输出的是输入的最后一个字符。例如,我预计123 456 的输出为 ,但实际上是6。同样,我预计123456 的输出会出现一些错误,因为我们尝试访问一个尚不存在的元素输出又是。我错过了什么?

【问题讨论】:

std::istream_iterator 是一个输入迭代器。根据 cppreference.com 的说法,由于某些不清楚的原因,只有采用执行策略参数的重载被指定为需要前向迭代器。如果没有执行策略参数,find_if 只需要输入迭代器。在我看来,这个问题中的例子证明这是一个明显的缺陷。 std::find_if 应该需要前向迭代器,而不是输入迭代器。 It seems you can use istream_iterator&lt;int&gt;() for similar tasks. @SamVarshavchik -- 我不知道你是否正确std::find_if 应该总是至少需要一个前向迭代器,但执行策略版本需要前向迭代器的原因是 所有 采用执行策略的算法都需要前向迭代器或更好的迭代器。将并行算法应用于输入迭代器指定的序列是行不通的;该算法将不得不依靠串行版本。 【参考方案1】:

为什么123 456 作为输入不产生 作为输出?

来自cppreference:

读取字符时,std::istream_iterator 默认会跳过空格(除非使用 std::noskipws 或等效项禁用),而 std::istreambuf_iterator 不会。

切换到std::istreambuf_iterator 会产生所需的行为:https://wandbox.org/permlink/RRt8kvyqyvbO1p8m


为什么123456 作为输入不会产生错误?

如果输入中没有空格,find_if 将返回其第二个参数,即 end-of-stream 迭代器。

取消引用流结束迭代器是undefined behaviour,不保证会产生错误。事实上,它并不能保证任何事情,这意味着您的程序可能只打印输入中的最后一个字符。

【讨论】:

谢谢!我能问你为什么你的输出是0吗?在我的机器上,它按预期是空白的。这是一个依赖于实现的东西吗?另外,由于 std::istream_iterator 跳过了空格,我的版本不应该只产生错误或取消引用超出范围的迭代器给出的任何内容吗? 0 不是输出,而是main() 返回的值。如果选择输出,您可以看到 Start 和 0 之间有一个空格。取消引用过去的迭代器是未定义的行为,这意味着您的程序不再合理地运行.而且它的不合理性可能只是打印您输入中的最后一个字符;否则它可能会崩溃;或完全做其他事情。 我明白了!谢谢你的详细解释!

以上是关于为啥在 std::istream_iterator 上使用的 std::find_if 似乎返回最后一个元素?的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::copy 时出错

从文件中读取数字

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥在参数周围使用 /*、*/ 以及为啥在提取数组长度时使用 >>>? [复制]

为啥 CoreGui Roblox 锁定在 DataModel 中,为啥受信任的用户不能使用 CoreScripts?

为啥 + 仅在客户端是 NaN?为啥不在 Node.js 中?