std::exclusive_scan是C++17引入的并行算法,用于计算严格前缀和(即每个位置结果不含当前元素),适用于累积偏移量、构建索引映射表或预分配区间边界等场景。

std::exclusive_scan 是什么,适合解决哪类问题
它是在 C++17 引入的并行算法,用于计算**严格前缀和**(即每个位置的结果不包含当前元素),等价于手动写循环做 out[i] = in[0] + in[1] + ... + in[i-1]。典型场景是:需要累积偏移量、构建索引映射表、或为后续并行操作预分配区间边界——比如把一组长度 {2, 5, 3} 转成起始偏移 {0, 2, 7}。
基本用法与参数顺序不能错
函数签名是:std::exclusive_scan(first, last, d_first, init, binary_op)。最容易出错的是前三个迭代器参数顺序和 init 的含义:
-
first和last是输入范围,[first, last)闭开区间 -
d_first是输出起始位置,必须保证足够空间(至少last - first个元素) -
init是**首个输出值**,也就是out[0],不是“初始累加值”——它直接赋给第一个结果,之后才开始累加 -
binary_op可选,默认是std::plus(),但若传了就必须显式写出类型,比如std::multiplies()
示例:
std::vectorv = {1, 2, 3, 4}; std::vector out(v.size()); std::exclusive_scan(v.begin(), v.end(), out.begin(), 0); // out == {0, 1, 3, 6}
和 std::inclusive_scan、std::partial_sum 的关键区别
三者都算前缀和,但语义不同:
立即学习“C++免费学习笔记(深入)”;
-
std::exclusive_scan:结果中第 i 项 = 前 i 项和(不含第 i 项),长度同输入,首项由init指定 -
std::inclusive_scan:结果中第 i 项 = 前 i+1 项和(含第 i 项),首项 = 输入首项 -
std::partial_sum(C++98 就有):行为等价于inclusive_scan,但不支持自定义二元操作的并行执行,也不接受init
如果误把 exclusive_scan 当作 partial_sum 用,会发现结果整体右移一位且首项多出一个 0,这是最常被忽略的语义偏差。
实际使用时容易踩的坑
几个高频问题:
- 输出容器没预留空间,导致
d_first迭代器失效(尤其用back_inserter时不行,必须提前 resize 或用 vector 构造) - 对浮点数使用默认
std::plus时,未考虑结合律失效带来的精度差异(并行执行下求和顺序不确定) - 传入
binary_op但没指定模板参数,如写成std::exclusive_scan(..., 0, std::multiplies)会编译失败,必须写std::multiplies()或std::multiplies() - 输入/输出范围重叠且非同一容器时,行为未定义;同一容器上原地计算需确保是
exclusive_scan(inclusive_scan不允许原地)
真正要靠它提速,得配合执行策略,比如加 std::execution::par_unseq;但小数据量反而更慢,别盲目加。









