填相同值必须用std::fill,填递增序列只能用std::iota;数组用std::fill(begin,end,val),vector优先assign,array用fill成员函数;iota起始值需防回绕,fill无边界检查易越界。

你需要在运行时对 C++ 数组或容器做快速批量初始化,但不确定该用 std::fill 还是 std::iota——选错不仅编译失败、越界崩溃,还会让逻辑结果完全偏离预期,比如想填全 42 却得到 42,43,44…,这种错误在调试阶段极难定位。
填相同值:必须用 std::fill,别碰 iota
第一步:对 C 风格数组,写 std::fill(std::begin(arr), std::end(arr), 42)。这比 std::fill(arr, arr + 10, 42) 安全得多——数组大小改了,这行代码不用动;而硬编码的 10 很快就会和实际长度脱节。
第二步:对 std::vector,直接调用 v.assign(n, 42),不要用 std::fill(v.begin(), v.end(), 42)。后者只修改已有元素,若 v 是空的,它什么也不做;assign 则会自动扩容并设值,语义完整。
第三步:对 std::array,优先用成员函数 a.fill(42)。它不依赖 <algorithm></algorithm> 头文件,不涉及迭代器运算,也不会因类型推导出错——C++11 起就支持,简洁且零风险。
注意:【std::fill 不做任何边界检查,传入非法范围(如 arr + 11 对 int arr[10])将直接越界写入,可能踩坏栈上相邻变量,调试器未必报错】。
填递增整数序列:只能用 std::iota,fill 无法替代
方法一:对原生数组 int idx[5],写 std::iota(idx, idx + std::size(idx), 100)。结果是 {100, 101, 102, 103, 104}。第三个参数是首个元素值,不可省略;漏掉它编译直接失败。
方法二:对 std::vector<int></int>,用 std::iota(v.begin(), v.end(), 0)。它天然适配容器大小变化,无需手算长度;若用 std::iota(v.data(), v.data() + v.size(), 0),虽等价,但多一层指针转换,无必要。
方法三:对 std::array<unsigned char></unsigned>,起始值必须严格控制——写 std::iota(a.begin(), a.end(), 253) 会生成 {253, 254, 255, 0}。这不是 bug,是标准规定的回绕行为;若业务逻辑要求“严格递增不回绕”,这个起始值就错了。
性能关键真相:优化能力取决于编译器,不是你写的函数名
在 GCC/Clang -O2 下,std::fill(ptr, ptr + N, 0) 对 int 或 char 数组大概率被优化为 memset,速度逼近内存带宽极限;但填非零值如 42,多数情况下不会触发 memset,而是走向量化 store 指令。
std::iota 几乎无法 SIMD 化——每个新值都依赖前一个 ++value 的结果,CPU 必须串行执行。实测 10M 元素的 int 数组,std::iota(..., 0) 比 std::fill(..., 0) 慢约 40%,差距来自硬件流水线阻塞,不是算法复杂度问题。
小数组(
真正该优先考虑的初始化方式,往往不是 fill 或 iota
如果值在编译期已知,比如要初始化一个 1024 元素的全零栈数组,直接写 int arr[1024] = {};。这由编译器生成最优机器码,可能是 .data 段置零,也可能是单条 xor eax, eax 清寄存器后 rep stosd,零运行时开销。
对静态存储期对象(如全局数组),= {} 初始化甚至不占可执行代码空间,纯数据段描述;而 std::fill 和 std::iota 都是运行时函数调用,必然有指令、有栈帧、有分支预测开销。
【声明即初始化不触发任何函数调用,也不依赖头文件包含或命名空间,是最安全、最快、最可移植的初始化方式】。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











