【问题标题】:istream_iterator consumes too much from streamistream_iterator 从流中消耗太多
【发布时间】:2017-04-02 02:08:00
【问题描述】:

我从标准输入得到以下输入:

2
5
2 1 5 3 4
5
2 5 1 3 4

第一行代表队列的数量(我们称这个值n)。然后,对于每个队列,在第一行有一个值l,表示队列的长度,然后是实际队列。

我正在尝试使用istream_iterator 将队列放入向量中,如下所示:

using namespace std;
int n{};
int l{};
typedef std::istream_iterator<int> input_iterator;
cin >> n;
cout<< "n: " << n << "\n";
for(int i = 0; i < n ; ++i){

    cin >> l;
    cout << "l: " << l << "\n";
    std::vector<int> queue;
    int counter = 0;
    for (input_iterator it(cin); counter < l && it != input_iterator(); ++it){
        queue.push_back((*it));
        ++counter;
    }
    cout<< "Queue: ";
    std::copy(queue.begin(), queue.end(), 
                  std::ostream_iterator<int>(std::cout, " "));
    cout << "\n";
}

此代码产生以下输出:

n: 2
l: 5
Queue: 2 1 5 3 4 
l: 2
Queue: 5 1 

如您所见,第一个队列被正确读取。但是第二个l 应该是5,而不是2

5 发生了什么事?它被迭代器消耗了吗?我哪里出错了?

【问题讨论】:

  • 在调试器中逐行执行代码。并停止隐藏变量,在内循环中为迭代器使用另一个名称。此外,您是否有理由要使用输入迭代器,而不仅仅是使用简单的std::cin &gt;&gt; ... 获取值的普通循环?
  • 那个和整个阴影的事情实际上是编写这个例子时发生的一个错误。我修好了

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


【解决方案1】:

您的问题是您的 for 循环将 i 留在队列最后一个元素旁边的位置。所以当调用operator&gt;&gt; 来获取l 的下一个值时,你是一个“阅读步骤”太远了。

为避免此问题,您可以对所有读取操作使用相同的迭代器 - 并重命名它以避免与外部循环中的变量 i 发生名称冲突,如下所示:

using namespace std;
int n{};
int l{};
typedef std::istream_iterator<int> input_iterator;
cin >> n;
cout<< "n: " << n << "\n";
input_iterator it(cin);
for(int i = 0; i < n ; ++i){

    l = *(it++);
    cout << "l: " << l << "\n";
    std::vector<int> queue;
    int counter = 0;
    while( counter < l && it != input_iterator() ){
        queue.push_back(*(it++));
        ++counter;
    }
    cout<< "Queue: ";
    std::copy(queue.begin(), queue.end(), 
                  std::ostream_iterator<int>(std::cout, " "));
    cout << "\n";
}

【讨论】:

    【解决方案2】:

    IANALL,但据我所知,istream_iterator 允许在其operator++() 中提前阅读。由于您正在为您读取的每个组(数字行)重新创建一个 istream 迭代器,因此您正在丢弃一个已经从输入流中读取下一个整数的迭代器。

    一种解决方案是在 for 循环之外只创建一次输入迭代器并在整个过程中使用它。

    【讨论】:

      【解决方案3】:

      for 循环基本上只是一个花哨的while 循环。

      让我们从您的代码中获取这个for 循环:

      for (input_iterator it(cin); counter < l && it != input_iterator(); ++i){
          queue.push_back((*it));
          ++counter;
      }
      

      相当于如下:

      {
          input_iterator it(cin);
          while (counter < l && it != input_iterator())
          {
              queue.push_back((*it));
              ++counter;
              ++it;
          }
      }
      

      注意到循环中的最后一行,++it; 语句吗? 这就是导致您的问题的原因。它会增加一次迭代器太多,所以在循环之后迭代器已经读取了输入中的5。循环之后的下一个输入操作将读取下一行中的2

      一种解决方案是保留迭代器,并在外循环中重用它。也许将它用于所有输入。

      我在评论中暗示的另一个解决方案是让 for 从零循环到 l 并且根本不使用迭代器,而只使用普通的 cin &gt;&gt; ...

      【讨论】:

        猜你喜欢
        • 2016-05-17
        • 2020-04-16
        • 2011-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-16
        相关资源
        最近更新 更多