【问题标题】:simple istream_iterator question简单的 istream_iterator 问题
【发布时间】:2011-09-15 18:32:54
【问题描述】:

我是 C++ 新手,如果这是一个愚蠢的问题,我很抱歉。我似乎无法弄清楚为什么这不起作用。它复制到第一个向量中,并且似乎跳过了第二个复制调用。

#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

int main ()
{
    vector<int> first;
    vector<int> second;

    copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(first));
    cin.clear();
    copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(second)); 
    return 0;
}

我想使用复制函数将 istream_iterator 输入读入任意数量的向量(每个向量一次调用复制)。换句话说:我希望能够在控制台中输入“1 2 3 4 5 ctrl+d”并将 1,2,3,4,5 输入到第一个向量中。然后在控制台中输入“6 7 8 9 10 ctrl+d”并将 6,7,8,9,10 输入到第二个向量中。

问题是当我在第一个向量中输入一些输入并按下 control+d 后,cin 的 istream_iterator 仍然等于 istream_iterator(),无论 cin 的失败状态如何。这会导致每次对“复制”的后续调用都失败(因为 istream_iteratorcin 已经等于程序解释为 eof 的 istream_iterator())。 所以我的问题是:我需要做什么来“重置”迭代器以及 cin 流? cin.clear() 确实清除了所有失败位。然而 istream_iterator(cin) 仍然等于 istream_iterator() 无论如何。据我了解,绑定到流的 istream_iterators 仅应在流处于失败状态时等于默认的 istream_iterator 值。我错过了什么?

【问题讨论】:

  • 定义How it should workwhat is not working
  • 我正在尝试在标准输入中输入一些数字并将这些整数复制到第一个向量中,直到我按 ctrl-d 时第一个副本将停止。然后我想清除标准输入的失败状态并重复将数字复制到第二个向量的过程。问题是它复制到第一个但不复制到第二个,因为不知何故 istream_iterator(cin) 仍然等于 istream_iterator()。我认为清除失败状态并调用 istream_iterator(cin) 会给我一个不等于默认 istream_iterator 值的新迭代器。
  • 我无法复制。我输入第一组值 ^D,输入第二组值 ^D,程序以正确的输出终止(我正在转储要检查的向量元素)。
  • 卢克,真的吗??您使用的是完全相同的代码,它对您有用吗??
  • This 是我的程序的样子和我输入的内容(每行后有一个 ^D)。 Ideone 只一次性传递整个输入,所以它最终都在第一个向量中,并不代表我正在做的事情。

标签: c++ copy istream-iterator


【解决方案1】:

istream_iterator 是一个输入迭代器,这意味着您只能取消引用每个迭代器值一次。您实际上是在从流中阅读,并且没有寻找或返回。因此,一旦您到达流的末尾,就没有更多的输入,并且第二个范围是空的。

为什么不直接说vector&lt;int&gt; second(first); 来复制?


更新:在您澄清问题后,这里有一个新答案:您误解了 stdin 的工作原理。只有 一个 输入。 Ctrl-D 不是 C++ 所固有的;相反,这是您平台的约定,当您发出Ctrl-D 信号时,您的平台将终止输入缓冲区。之后,输入的“文件”就完成了,不能再往里面写数据了。

不过,您的方法有点不正统。通常,您只需逐行阅读,以Enter 分隔,并对每一行进行标记。使用字符串流,你会得到非常相似的代码:

std::string line;
std::vector<int> first, second;

// Read line 1
if (std::getline(std::cin, line))
{
  std::istringstream iss(line);
  std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(first));
}
else { /* error */ }

// Read line 2
if (std::getline(std::cin, line))
{
  std::istringstream iss(line);
  std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(second));
}
else { /* error */ }

【讨论】:

  • 感谢您的快速回复!我确实意识到制作副本有更简单的方法,我只是想更好地理解 istream_iterators 的工作原理。因此,如果我理解正确,一旦我在使用 istream_iterator 读取输入时按下 control+d,那么迭代器在此之后基本上就变得无用了吗?有没有办法“重置”或“重新实例化”迭代器以便我可以再次读取它?
  • @Kaleetos:本质上,这与阅读stdin 相同。你不能回去。一旦你读取数据,它就会从输入缓冲区中消失。
  • 很公平,但是还有其他一些技术可以让我稍后再次使用 istream_iterator(stream) 吗?也许我应该使用自己的终止符值而不是使用默认的 istream_iterator 值?这对我来说似乎很奇怪,因为这种将输入复制到字符串中的特殊方法是我在许多网站上发现的一个常见示例(在我正在阅读的书中)。所以我觉得很奇怪,没有提到这个方法一旦在程序中使用一次就不能再使用了。
  • @Kaleetos:我不确定你想要实现什么。如果您想要其他类型的数据源,请不要使用cin...也许更新您的问题以准确解释您的目标和问题。
  • 我更新了Kerrek的问题。我想我在回复您的第一个答案时说“我知道有更简单的方法可以制作副本”时我可能会误导您。我实际上并没有尝试复制向量——而是尝试使用复制函数将标准输入输入值读入多个向量(通过 istream_iterators)。我希望上面编辑过的问题能更好地解释它!
猜你喜欢
  • 1970-01-01
  • 2011-10-31
  • 2011-01-29
  • 2018-03-07
  • 2011-10-30
  • 2013-02-17
  • 2011-02-24
  • 1970-01-01
相关资源
最近更新 更多