为什么从分配给变量的istream_iterator读取不起作用?



我编写了以下程序,从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), 
3, 
std::ostream_iterator<int>(std::cout, " "));              
}

对于1 2 3 4 5 6的输入,程序打印预期的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, 3, outs);
std::copy_n(ins, 3, outs);
}

但是现在对于输入1 2 3 4 5 6,程序打印1 2 3 1 4 5

我不明白输出。这是怎么回事,我做错了什么?

另外,请注意,只有当我使用ins时才重要。无论我是否使用outs都不会影响输出。

根据此参考:

std::istream_iterator 是一个单通道输入迭代器,它通过调用相应的运算符>>,从构造它的 std::basic_istream 对象中读取 T 类型的连续对象。实际的读取操作是在迭代器递增时执行的,而不是在取消引用时执行的。构造迭代器时读取第一个对象。取消引用仅返回最近读取的对象的副本。

因此,当您首次创建ins变量时,它会立即从cin读取1并对其进行缓存。

如果你看一下copy_n()的声明,输入迭代器是按值传递的,这意味着它是被复制的

template< class InputIt, class Size, class OutputIt >
OutputIt copy_n( InputIt first, Size count, OutputIt result );

为了论证起见,让我们假设正在使用以下copy_n()实现(检查编译器的实际实现):

template< class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, 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()递增firstcin读取2并缓存它,然后取消引用first以接收2并输出它,然后递增firstcin读取3并缓存它,然后取消引用first以接收3并输出它,然后退出。

再次将ins传递给copy_n()时,原始缓存1仍处于ins中,并复制到first参数中。当copy_n()取消引用first时,它接收缓存的1并输出到result。然后copy_n()递增firstcin读取4并缓存它,然后取消引用first以接收4并输出它,然后递增firstcin读取5并缓存它,然后取消引用first以接收5并输出它,然后退出。

如果您查看缺陷报告P0738R2,您将看到istream_iterator的第一次读取应由构造函数执行,因此它在auto ins = ...行读取1

copy_n值获取其参数,因此第一次调用不会将main()ins变量移动到它已经读取的1,并且再次提供给copy_n的第二次调用。

如果你想要简洁,你可以做这样的事情:

auto mkins() = [] { return std::istream_iterator<int>(std::cin); }
std::copy_n(mkins(), 3, outs);
std::copy_n(mkins(), 3, outs);

相关内容

最新更新