为何经过转换的范围没有有效迭代器?
为何经过转换的范围没有有效迭代器?
我最近在处理C++输入流视图的时候遇到了一个棘手的问题,先给大家看看我的代码:
首先,我想从输入流中获取字符的视图,这段代码运行得很顺利:
auto input = std::stringstream{"abcd"}; using Iter = std::istreambuf_iterator<char>; auto s = std::ranges::subrange{Iter{input}, Iter{}};
可当我给这个视图加上一个转换操作(为了测试方便,用了恒等变换)之后:
auto t = s | std::views::transform(std::identity{});
怪事发生了——这个转换后的视图明明有合法的value_type,但它的迭代器却好像没法正常工作。这到底是怎么回事呢?
其实问题的核心在于std::istreambuf_iterator属于输入迭代器,而std::views::transform在处理输入迭代器时,会保留它的迭代器类别特性。输入迭代器的特点是只能被单次遍历,而且不支持重复访问、前后移动等操作,它的operator==也只能用来和尾迭代器比较。
当我们用subrange包装输入迭代器后,生成的范围迭代器依然是输入迭代器范畴。经过transform视图包装后,新的迭代器并没有升级迭代器类别,还是输入迭代器。如果你用对待前向迭代器或者随机访问迭代器的方式去使用它——比如尝试多次遍历、保存迭代器后复用,就会出现“迭代器无效”的假象。
另外还有个细节需要注意:std::istreambuf_iterator在构造时就可能开始读取流内容,它的状态和输入流的状态紧密绑定。当流的指针移动到末尾后,迭代器自然就无法再访问元素了,这也会让你误以为迭代器失效。
说白了,不是转换后的范围没有有效迭代器,而是这个迭代器的行为模式和你熟悉的其他迭代器不一样,只要遵循输入迭代器的使用规则,它就能正常工作啦。
备注:内容来源于stack exchange,提问作者Toby Speight
相关产品推荐
相关产品推荐

