std::fill 赋值后数组元素全相同,因其语义是将指定范围统一设为同一值;它不支持递增逻辑,适合清零或设默认值,而递增初始化应使用 std::iota。

用 std::fill 初始化数组时,为什么赋值后全是同一个值?
std::fill 的作用是把指定范围填成「同一个值」,不是生成序列。它适合清零、设默认标记等场景,但不适合递增初始化。
常见错误:误以为 std::fill 能像 Python 的 range() 那样自动递增:
int arr[5]; std::fill(arr, arr + 5, 0); // ✅ 全设为 0 std::fill(arr, arr + 5, i++); // ❌ i 未定义;且 fill 不接受表达式求值逻辑
- 参数必须是常量或左值,不能是带副作用的表达式(如
i++) - 底层调用的是赋值操作符,对每个元素独立执行
arr[i] = value - 性能极好 —— 编译器通常优化为内存块写入(类似
memset,但支持任意类型)
想让数组变成 0,1,2,3,4?直接上 std::iota
std::iota 是专为“递增序列”设计的,名字来自 APL 语言的 ι(iota)函数,语义就是「从某起点开始逐个加 1」。
正确用法:
立即学习“C++免费学习笔记(深入)”;
int arr[5];
std::iota(arr, arr + 5, 0); // arr → {0,1,2,3,4}
- 第三个参数是起始值,类型需与数组元素兼容(比如
double数组可用0.0) - 它不检查溢出,
char arr[3]; std::iota(arr, arr+3, 100);会得到{100,101,102},可能截断 - 要求迭代器支持
operator+=,所以不能用于std::vector<bool></bool>这类代理迭代器
std::fill 和 std::iota 能用在 std::vector 上吗?
完全可以,而且更常用 —— 因为 std::vector 的 data() 返回原生指针,可直接传给这两个算法:
std::vector<int> v(5);
std::fill(v.begin(), v.end(), -1); // ✅ 等价于 std::fill(v.data(), v.data() + v.size(), -1)
std::iota(v.begin(), v.end(), 10); // ✅ 得到 {10,11,12,13,14}
- 推荐统一用
begin()/end(),语义清晰,适配所有标准容器(deque、array也行) - 注意
std::array需要 .data()或取地址:std::iota(a.data(), a.data() + a.size(), 0) - 不要对空容器调用
iota—— 虽然标准允许,但若起始值是自定义类型且构造/赋值有副作用,可能意外触发
初始化性能差异大吗?什么时候该选哪个?
两者底层都是循环赋值,现代编译器优化后性能几乎无差别,关键看语义是否匹配。
- 填相同值(如清空、设 flag、初始化为 -1 表示无效)→ 用
std::fill - 生成等差序列(索引映射、ID 分配、测试数据)→ 用
std::iota - 需要非 +1 步长(如 ×2、+3)→ 两者都不适用,改用
std::generate+ lambda - 初始化大型 POD 数组且值为 0 →
std::fill可能被优化为memset,比手写 for 更稳
真正容易被忽略的是:它们都要求目标内存已分配 —— std::iota 不会扩容 vector,也不会构造对象;如果元素是类类型,必须确保已调用过构造函数(即容器 size 已确定,或数组已声明)。


















