【发布时间】:2014-06-11 15:25:34
【问题描述】:
我希望下面的 buf_iter 指向字符 n 字符在它开始的点之后。相反,它指向最后一个读取的字符。为什么是这样?即,如果我在 copy_n 之前和之后执行 in_stream.tellg(),它们的区别不是 n,而是 (n-1)。如果我用in_stream.read 读取n 字符,那么该位置将提高n。
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, n, sym.begin());
我查看了实现,它显然是故意这样做的,跳过了最后的增量。
另一篇帖子here 提到当从迭代器连接到cin 时递增它会导致读取次数过多,因为读取是在operator++() 上完成的。这听起来像是cin 的问题——为什么没有在operator*() 上完成读取?
标准是否在任何地方指定了这一点?我看到的文档没有提到 from 迭代器会发生什么,而且我看到了两个不同的页面,它们提供了执行每种行为的“可能的正确实现”:
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;
}
while at cplusplus.com we have:
template<class InputIterator, class Size, class OutputIterator>
OutputIterator copy_n (InputIterator first, Size n, OutputIterator result)
{
while (n>0) {
*result = *first;
++result; ++first;
--n;
}
return result;
}
两者都不读取并在结果中产生相同的内容。但是,第一个只会将“第一个”迭代器增加n-1 次,而第二个会将它增加n 次。
什么给了?如何编写可移植代码?我可以使用tellg,然后使用seekg,但我还不如手动循环(啊!)。
请注意,我不是在调用copy_n 后尝试从迭代器中读取,而是在调用copy_n 后从底层流中读取,问题是copy_n 指向短字节在我预期的地方。现在我要使用有点可怕但显然是便携的:
auto pos = in_stream.tellg();
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, cl, sym.begin());
in_stream.seekg(pos + cl);
uint64_t foo;
in_stream.read(reinterpret_cast<char *>(&foo), 8);
顺便说一句,如果不清楚,我会尽量避免将数据复制到缓冲区中,然后再复制到字符串sym。
@DaveS:离开我的具体问题,这里有一个简单的程序,由于输入迭代器最后一次没有递增,所以它没有输出我所期望的:
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
int main(int argc, const char * argv[])
{
std::ifstream in("numbers.txt");
std::istreambuf_iterator<char> in_iter(in);
std::ostreambuf_iterator<char> out_iter(std::cout);
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
std::copy_n(in_iter, 3, out_iter);
std::cout << std::endl;
return 0;
}
输入文件就是"0123456789\n"
我明白了:
012
234
456
由于istreambuf_iterator::operator++() 的副作用,如果实现copy_n 以增加输入迭代器n 倍,这将给出不同的结果。
@aschepler:需要捕获本地参数,但我会用它:
std::generate_n(sym.begin(), cl, [&in_stream](){ return in_stream.get(); });
【问题讨论】:
-
或者怎么样:
std::generate_n(sym.begin(), cl, [](){ return in_stream.get(); });? -
我询问了 C++ 标准讨论邮件列表。也许有人可以解释原因。主题在这里:groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/…