Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么std::istream\u迭代器<&燃气轮机;使用多副本时,\n()始终写入第一个值_C++_Algorithm_Istream Iterator - Fatal编程技术网

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