C++ 为什么std::istream\u迭代器<&燃气轮机;使用多副本时,\n()始终写入第一个值
我试图将输入行复制到多个向量中:C++ 为什么std::istream\u迭代器<&燃气轮机;使用多副本时,\n()始终写入第一个值,c++,algorithm,istream-iterator,C++,Algorithm,Istream Iterator,我试图将输入行复制到多个向量中: #include <vector> #include <sstream> #include <istream> #include <iterator> #include <algorithm> #include <iostream> int main(){ std::vector<int> v1, v2, v3; std::istringstream is ("
#include <vector>
#include <sstream>
#include <istream>
#include <iterator>
#include <algorithm>
#include <iostream>
int main(){
std::vector<int> v1, v2, v3;
std::istringstream is ("1 2 3 4 5 6");
std::istream_iterator<int> iit (is);
std::copy_n(iit, 2, std::back_inserter(v1));
std::copy_n(iit, 2, std::back_inserter(v2));
std::copy(iit, std::istream_iterator<int>(), std::back_inserter(v3));
std::ostream_iterator<int> oit(std::cout, ", ");
std::copy(v1.begin(),v1.end(), oit);
std::cout << "\n";
std::copy(v2.begin(),v2.end(), oit);
std::cout << "\n";
std::copy(v3.begin(),v3.end(), oit);
std::cout << "\n";
return 0;
}
但我明白了:
1, 2,
1, 3,
1, 4, 5, 6,
为什么复制总是在向量的开头插入1?这可以归结为
istream迭代器
的一个可能不直观的事实:取消引用时它不会读取,而是读取
我们仍然希望通过
*it
向我们提供数据。因此,为了实现这一点,读取数据的每一位都必须临时存储在迭代器本身中,直到我们下一次执行*it
因此,当您创建iit
时,它已经为您拉出了第一个数字,1
。该数据存储在迭代器中。流中的下一个可用数据是2
,然后使用copy\n
将其取出。总的来说,在您要求的总共两条信息中,有两条信息已发送,因此第一条拷贝已完成
下一次,您使用的是iit的副本,其状态与第一次copy\n
之前的状态相同。因此,尽管流已准备好为您提供3
,但您仍有一份1
“卡”在复制的流迭代器中。
为什么要使用流迭代器?因为在尝试获取更多数据之前,无法检测流上的EOF。如果它不是这样工作的,你必须先做一个解引用来触发这个检测,然后如果我们达到EOF,结果应该是什么
此外,我们期望任何解引用操作都能立即产生结果;对于给定的容器,但对于流,您可能会阻塞等待数据可用。相反,在构造/增量上执行这种阻塞更有逻辑意义,因此迭代器总是有效的或无效的
如果您取消副本,并为每个副本构建一个新的流迭代器,您应该可以。尽管我通常建议每个流只使用一个流迭代器,因为这样可以避免任何人担心这一点。如果您阅读,请结合以下事实:所示代码将迭代器按值传递给std::copy\n
,并且std::copy\n
修改迭代器,然后显示的代码试图使用相同的迭代器原始值,你能从中得出什么结论?@SamVarshavchik你说的是:“当迭代器被构造时,第一个对象被读取”?因此,每次使用副本时,我可能必须创建一个新的istream_迭代器?因此,当您建议每个流使用一个流迭代器时。这是否意味着每次在copy或其他任何地方使用迭代器时都要创建一个新的迭代器?事实上,是的,这也很好。让我知道它是怎么回事。@FedorGoncharov,一条小溪就像。。。一条小溪,一条河。一旦有一大块流经过,你就再也看不到它了。@EnricoMariaDeAngelis(对于某些类别的流;)但是,将它们视为数据流,而不是容器,当然是有帮助的。我指的是我所知道的唯一一个概念,即流;什么样的溪流是适合的?
1, 2,
1, 3,
1, 4, 5, 6,
(x indicates a read)
Normal forward iterators:
Data: 1 2 3 (EOF)
Construction
*it x
++it
*it x
++it
*it x
++it (`it` is now the one-past-the-end iterator)
Destruction
Stream iterators:
Data: 1 2 3 (EOF)
Construction x
*it
++it x
*it
++it x
*it
++it (`it` is now the one-past-the-end iterator)
Destruction