std::fill用于填充相同值,std::iota仅生成公差为1的递增整数序列,二者语义不同、不可互换;填错范围或类型会导致崩溃、UB或编译失败,性能差异源于优化路径而非算法复杂度。

直接说结论:std::fill 用来填相同值,std::iota 只能填公差为 1 的递增整数序列——二者语义完全不同,不存在“哪个更快所以该选谁”的问题,选错就编译失败或行为错误。
std::fill 填相同值,但传错迭代器范围会直接崩溃
std::fill 不做边界检查,只按你给的 [first, last) 范围逐个赋值。传错 last 是最常见、最危险的错误。
- 对 C 风格数组
int arr[10],必须写std::fill(arr, arr + 10, 42);写成arr + 9漏最后一个,arr + 11就越界 UB - 用
std::begin(arr)和std::end(arr)更安全,C++11 起支持,且数组大小变化时不用改数字 - 对
std::vector,别在空容器上调用std::fill(v.begin(), v.end(), x)——它什么也不做,因为begin() == end();先v.resize(n)或直接用v.assign(n, x) - 对
std::array,优先用成员函数a.fill(x)(C++11),不依赖<algorithm></algorithm>,也更短
std::iota 填递增序列,但不是“等差数列通用工具”
std::iota 的行为是:第 0 个位置赋 value,第 1 个赋 ++value(前置递增),第 2 个再 ++value……它不接受步长参数,也不支持倒序或浮点精确步进。
- 想填
{10, 20, 30}?std::iota做不到,得用std::generate配 lambda:[n = 10]() mutable { return (n += 10); } - 对
unsigned char buf[5]调用std::iota(buf, buf + 5, 254),第二个元素就溢出,结果未定义 - 对
std::vector<double></double>用std::iota,第 100 万个元素可能偏离理论值超过 0.1,因浮点累加误差不可控 - 对
std::string数组或自定义类,std::iota编译失败——它要求类型支持operator++,而std::string没有
性能差异其实很小,但优化路径完全不同
两者都是 O(n) 线性遍历,真实差距不在算法,而在编译器能否识别模式并替换为底层指令。
-
std::fill(ptr, ptr + n, 0)在 GCC/Clang -O2 下大概率被优化为memset,尤其对int或char数组,速度接近内存带宽极限 -
std::fill(ptr, ptr + n, 42)对非零多字节值,不一定触发memset;但现代编译器常能向量化为 AVX store,未必比手写循环慢 -
std::iota几乎无法 SIMD 化,因为每个值依赖前一个;实测 10Mint数组上,它比std::fill(..., 0)慢约 30%~50%,主因是 load-modify-store 链和加法延迟 - 小数组(
真正该优先考虑的初始化方式,往往不是 fill 或 iota
它们只是运行时填充手段。很多场景下,用错阶段反而绕远路。
- 静态/全局数组:
int arr[1024] = {};—— 零开销,编译期完成,不占运行时时间 - 栈上小数组:
std::array<int> a = {};</int>—— 类型安全,自动调用默认构造 - 动态大小需求:
std::vector<int> v(1000, 42);</int>—— 构造即填充,一步到位,不暴露裸指针 - 需要非平凡逻辑(随机数、平方、条件值):
std::generate+ lambda,比硬套iota或写循环更简洁可靠
最容易被忽略的一点:所有这些函数都只对**已分配且已构造的对象**执行赋值,不会调用构造函数。如果你的类依赖构造过程申请资源,用 std::fill 或 std::iota 初始化其数组,会导致对象处于未定义状态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











