我希望以下内容让buf_iter
指向字符n
字符后面的字符。相反,它指向最后一个字符读取。为什么是这样?即如果我在copy_n之前和之后进行in_stream.tellg(),它们的区别不是n
而是(n-1)
。如果我使用n
阅读in_stream.read
个字符,那么该位置将按n
提前。
std::istreambuf_iterator<char> buf_iter(in_stream);
std::copy_n(buf_iter, n, sym.begin());
我已经查看了实现,它显然是故意这样做的,跳过最后的增量。
另一篇帖子here提到,当它连接到cin
时,从迭代器递增会导致读取次数过多,因为operator++()
上的读取已完成。这听起来像cin
的问题 - 为什么不在operator*()
上完成阅读?
标准是否在任何地方指定了这个?我见过的文档没有提到迭代器发生了什么,我看到两个不同的页面提供了“可能正确的实现”来执行每个行为:
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);
BTW,如果不清楚,我试图避免将数据复制到缓冲区然后再次进入字符串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(); });
答案 0 :(得分:7)
n3797 [algorithms.general] / 12
在算法的描述中,运算符
的语义相同+
和-
用于某些迭代器类别,而不必定义它们。在这些情况下,a+n
的语义与X tmp = a; advance(tmp, n); return tmp;
和
相同b-a
的内容与return distance(a, b);
[alg.modifying.operations]
template<class InputIterator, class Size, class OutputIterator> OutputIterator copy_n(InputIterator first, Size n, OutputIterator result);
5 效果:对于每个非负整数 i&lt; n ,执行
*(result + i) = *(first + i)
。6 返回:
result + n
。7 复杂性:完全
n
作业。
我不确定它是否适用于InputIterators(没有多通道),因为它不会修改原始迭代器,但总是会推进原始迭代器的副本。它似乎也没有效率。
[input.iterators] /表107 - 输入迭代器要求(除迭代器外)
表达:
的范围++r
退货类型:X&
pre:r
是不可分辨的 帖子:r
可以取消引用或r
是过去的结尾 post:不再需要r
之前值的任何副本 可解除引用或属于==
。
据我所见,<{p>}中的a
因此,X tmp = a; advance(tmp, n); return tmp;
不再需要可递增。
相关缺陷报告:LWG 2173
答案 1 :(得分:7)
许多std::copy_n
实现增加n-1次的原因是由于与istream_iterator
的交互,以及通常如何实现。
例如,如果您有一个包含整数的输入文件
std::vector<int> buffer(2);
std::istream_iterator<int> itr(stream); // Assume that stream is an ifstream of the file
std::copy_n(itr, 2, buffer.begin());
因为istream_iterator
被指定为以递增方式读取(并且在构造或第一次取消引用时),如果std::copy_n
将输入迭代器递增2次,则实际上将读取文件中的3个值。当copy_n
内的局部迭代器超出范围时,第三个值将被丢弃。
istreambuf_iterator
没有相同的互动,因为它实际上并没有将流中的值复制到本地副本中,就像大多数istream_iterators
那样,但是{{1}仍然表现得这样。
编辑:如果copy-N增加N次,则丢失数据的示例(cplusplus.com描述,它似乎不正确)。注意,这实际上仅适用于copy_n
或其他在增量上读取和删除其基础数据的迭代器。
istream_iterators
答案 2 :(得分:2)
源迭代器不是通过引用获取的。因此,它的副本增加n次,但参数保持不变。
10次中有9次,这就是你想要的。
就具体增加InputIterators的副作用而言,我认为正式,输入迭代器应在每次读取时“递增”(没有增量的重复读取不产生相同的值) 。所以,只需将增量设为无操作。