gpt4 book ai didi

c++ - 为什么 std::copy_n 不增加输入迭代器 n 次?

转载 作者:IT老高 更新时间:2023-10-28 21:52:58 32 4
gpt4 key购买 nike

我希望下面的 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 迭代器会发生什么,而且我看到了两个不同的页面,它们给出了执行每种行为的“可能的正确实现”:

At cppreference we have:

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::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 那样将值从流中复制到本地拷贝中,但是 copy_n 仍然如此。

编辑:如果 copy-N 增加 N 次则丢失数据的示例(cplusplus.com 描述,这似乎不正确)。请注意,这实际上仅适用于 istream_iterators 或其他在增量时读取和删除其基础数据的迭代器。

std::istream_iterator<int> itr(stream); // Reads 1st value

while(n > 0) // N = 2 loop start
{
*result = *first;
++result; ++first; // Reads 2nd value
--n; // N: 1
// N = 1 loop start
*result = *first;
++result; ++first; // Reads 3rd value
--n; // N :0
// Loop exit
}
return result;

关于c++ - 为什么 std::copy_n 不增加输入迭代器 n 次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23301162/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com