std::views::transform搭配filter时函数调用次数异常咨询
现象原因
该现象是C++ ranges视图惰性求值特性+旧版本GCC标准库实现缺陷共同导致的,具体逻辑如下:
- 所有
std::views生成的视图都不会提前存储计算结果,只有在迭代访问元素的时候才会实时执行绑定的转换、过滤逻辑,属于惰性求值。 - 单独使用
std::views::transform生成v1时,迭代过程每访问一个元素只会触发一次square计算,遍历4个元素正好调用4次,和向量长度一致,符合预期。 - 链式调用
transform+filter生成v2时,GCC 10.3附带的libstdc++实现中,filter视图的迭代器没有缓存上游transform已经计算出的结果:- 迭代器移动时,会先调用
square计算当前元素值,传给isEven做奇偶判断 - 如果元素满足过滤条件(是偶数),后续下游
std::ranges::copy读取该元素值输出时,会再次调用square重新计算一次该元素的值 - 不满足过滤条件的奇数元素只会被计算一次,不会重复触发
- 迭代器移动时,会先调用
6次调用的具体计数拆解
对应输入向量{1,2,3,4},调用次数累加过程为:
- 处理元素1:调用
square得1,isEven判断为奇数过滤,累计1次 - 处理元素2:第一次调用
square得4,isEven判断为偶数保留;copy输出时第二次调用square取值,累计3次 - 处理元素3:调用
square得9,isEven判断为奇数过滤,累计4次 - 处理元素4:第一次调用
square得16,isEven判断为偶数保留;copy输出时第二次调用square取值,累计6次
注:该重复调用属于GCC 10.x版本libstdc++的实现bug,更高版本的标准库已经为filter迭代器增加了上游值缓存逻辑,修复后该场景下
square的调用次数会回归到和向量长度一致的4次。
内容的提问来源于stack exchange,提问作者HEKTO
相关产品推荐
相关产品推荐

