istream_iterator 从流中消耗过多
istream_iterator consumes too much from stream
我从标准输入得到以下输入:
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
发生了什么事?它被迭代器消耗了吗?我哪里出错了?
IANALL,但据我所知 istream_iterator 允许在其 operator++()
中提前阅读。由于您要为读取的每个组(数字行)重新创建一个 istream 迭代器,因此您将丢弃一个已经从输入流中读取下一个整数的迭代器。
一种解决方案是在 for 循环之外仅创建一次输入迭代器并在整个过程中使用它。
您的问题是您的 for 循环将 i
留在队列最后一个元素旁边的位置。因此,当调用 operator>>
以获取 l
的下一个值时,您 "reading step" 太过分了。
为避免该问题,您可以对所有读取操作使用相同的迭代器 -- 并重命名它以避免与外循环中的变量 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";
}
一个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
。
一个解决方案是保留迭代器,并在外循环中重用它。也许将它用于 all 输入。
我在评论中暗示的另一个解决方案是让 for
从零循环到 l
仅 并且不使用迭代器除了普通 cin >> ...
.
我从标准输入得到以下输入:
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
发生了什么事?它被迭代器消耗了吗?我哪里出错了?
IANALL,但据我所知 istream_iterator 允许在其 operator++()
中提前阅读。由于您要为读取的每个组(数字行)重新创建一个 istream 迭代器,因此您将丢弃一个已经从输入流中读取下一个整数的迭代器。
一种解决方案是在 for 循环之外仅创建一次输入迭代器并在整个过程中使用它。
您的问题是您的 for 循环将 i
留在队列最后一个元素旁边的位置。因此,当调用 operator>>
以获取 l
的下一个值时,您 "reading step" 太过分了。
为避免该问题,您可以对所有读取操作使用相同的迭代器 -- 并重命名它以避免与外循环中的变量 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";
}
一个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
。
一个解决方案是保留迭代器,并在外循环中重用它。也许将它用于 all 输入。
我在评论中暗示的另一个解决方案是让 for
从零循环到 l
仅 并且不使用迭代器除了普通 cin >> ...
.