距离导致我的迭代器“冻结”

4

试试这个:

int main()
{
    std::fstream fin_fout("some.txt");
    std::istream_iterator<std::string> beg(fin_fout),end;
    std::distance(beg,end);//if this line is commented out it works fine but not if is uncommented
    while (beg != end)
    {
      cout << *beg;
      ++beg;
    }
    return 0;
}

请发布一个可以编译和运行的完整代码。 - Yakov Galka
std::distance返回一个值。你是否有意不使用这个值? - RvdK
@Power 仅为此示例。 - smallB
1个回答

15

distance在输入迭代器上会重复调用operator++。然而,这个操作使得所有的迭代器副本无效,因为它们都引用相同的底层流。

这是合理的:考虑迭代器表示什么:输入流的当前状态。一旦你推进迭代器,状态就会改变。表示旧状态的所有其他迭代器现在都引用一个不存在的状态。

这就是为什么会看到这种行为。

从两个流操作中获取距离也不是有意义的操作,因为流没有固定的长度:流代表瞬态状态。


有什么想法为什么吗?它在副本上运行。第二个问题,有没有办法获取这些迭代器之间的差异,然后能够使用它们?但这是如此不自然的行为。 - smallB
1
@smallB:不,你不能复制一个流,因此流迭代器不操作副本。它操作的是流本身。因此,每个operator++调用都会提取流中的下一个项目。它改变了流本身,因此使指向该流的任何其他迭代器无效。在流中,只有两个位置有意义:迭代器可以指向当前元素,或者它可能指向流的“末尾”(end 迭代器)。两者之间的距离根本没有定义。(我需要从stdin读取多少内容才能到达流的末尾?) - jalf
@smallB 不,它不是在副本上运行,而是引用同一个基础流。你不能复制流。并且,没有办法得到差异,因为操作无意义,因为流没有长度。 - Konrad Rudolph
3
你不能笼统地概括这个案例。例如,“/dev/random”是一个“无尽”的文件。或者考虑网络流,本地计算机不知道资源的大小,或者正在被写入的日志文件。一般来说,确定文件流的长度是不可能的。虽然有特殊情况(比如你的情况),但流遍历器接口面向的是一般情况,而不是特殊情况。还有其他方法可以确定固定文件的长度,但不能通过迭代器实现。 - Konrad Rudolph
1
@MatthieuM。正如其他人所说,您可以使用输入迭代器调用distance,有时甚至可以得到正确的结果。话虽如此,我不知道这什么时候会有用,以及为什么允许这样做。在我看来,引发编译错误会更好。 - Konrad Rudolph
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接