问题描述
我编写了以下程序,该程序从std::cin
读取3个数字,并将它们输出到std::cout
,并执行两次:
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
std::copy_n(std::istream_iterator<int>(std::cin),3,std::ostream_iterator<int>(std::cout," "));
std::copy_n(std::istream_iterator<int>(std::cin)," "));
}
对于1 2 3 4 5 6
的输入,程序prints是预期的1 2 3 4 5 6
。
当我发现代码有点冗长时,我试图将迭代器存储在变量中:
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
auto ins = std::istream_iterator<int>(std::cin);
auto outs = std::ostream_iterator<int>(std::cout," ");
std::copy_n(ins,outs);
std::copy_n(ins,outs);
}
但是现在对于输入1 2 3 4 5 6
,程序prints 1 2 3 1 4 5
。
我不理解输出。这是怎么回事,我在做什么错了?
此外,请注意,仅当我使用ins
时才重要。是否使用outs
不会影响输出。
解决方法
std :: istream_iterator是单次输入迭代器,它通过调用适当的运算符>>从为其构造了std :: basic_istream对象中读取类型T的连续对象。实际的读取操作在迭代器增加时执行,而不是在取消引用时执行。构造迭代器时,将读取第一个对象。取消引用仅返回最近读取的对象的副本。
因此,当您首次创建ins
变量时,它将立即从1
中读取cin
并将其缓存。
如果您查看copy_n()
的声明,则输入迭代器将通过值传递,这意味着它已被复制。
template< class InputIt,class Size,class OutputIt >
OutputIt copy_n( InputIt first,Size count,OutputIt result );
为了论证,我们假设正在使用以下copy_n()
的实现(请检查编译器的实际实现):
template< class InputIt,class OutputIt>
OutputIt copy_n(InputIt first,OutputIt result)
{
if (count > 0) {
*result++ = *first;
for (Size i = 1; i < count; ++i) {
*result++ = *++first;
}
}
return result;
}
当您将ins
传递给copy_n()
时,该缓存的1
将被复制到first
参数中。当copy_n()
取消引用first
时,它将接收缓存的1
并输出到result
。然后copy_n()
递增first
,从2
读取cin
并将其缓存,然后取消引用first
以接收2
并输出,然后递增{ {1}}从first
读取3
并将其缓存,然后取消引用cin
以接收first
并输出它,然后退出。
再次将3
传递给ins
时,原始缓存的copy_n()
仍在1
中,并被复制到ins
参数中。当first
取消引用copy_n()
时,它将接收缓存的first
并输出到1
。然后result
递增copy_n()
,从first
读取4
并将其缓存,然后取消引用cin
以接收first
并输出,然后递增{ {1}}从4
读取first
并将其缓存,然后取消引用5
以接收cin
并输出它,然后退出。
如果您查看Defect Report P0738R2,将看到istream_iterator
的第一次读取应由构造函数执行,因此它在1
行读取auto ins = ...
。
copy_n
按值接受值,因此第一次调用不会将main()
的{{1}}变量移过它具有的ins
已经阅读,并且再次提供给1
的第二次调用。
如果您想简洁,可以执行以下操作:
copy_n