std::fill的作用是将指定范围内的所有元素统一赋为同一固定值,它不依赖索引或序列逻辑,仅执行重复赋值操作;因此结果必为全相同值,若需递增序列应改用std::iota。

用 std::fill 初始化数组时,为什么赋值后全是同一个值?
std::fill 的作用就是把一段内存区域统一设为某个固定值,它不生成序列、不依赖索引,只做“复制粘贴”式填充。如果你期望初始化为 {0,1,2,3,4} 却写了 std::fill(arr, arr+5, i++),那会出错——i++ 只求值一次,所有位置都填了初始的 i。
正确做法是明确区分“单值填充”和“序列填充”场景:
- 填充全零或全 -1:直接用
std::fill(arr, arr+N, 0)或std::fill(v.begin(), v.end(), -1) - 想填递增序列?别硬套
fill,换std::iota - 对
std::array使用时注意传迭代器:std::fill(a.begin(), a.end(), 42),不能传a本身 - 原始数组(如
int arr[10])可直接用指针:std::fill(arr, arr+10, 7)
用 std::iota 填充递增序列,起始值填错了怎么办?
std::iota 从指定起始值开始,按 ++ 操作逐个赋值,它不检查类型是否支持自增,也不做越界保护。常见翻车点:
- 起始值类型和容器元素类型不匹配:比如用
unsigned int start = 0去填std::vector<int8_t></int8_t>,可能溢出或隐式截断 - 填
char数组时忘了符号性:std::iota(buf, buf+26, 'a')没问题,但std::iota(buf, buf+26, -10)在char是unsigned的平台会绕成大正数 - 对空容器调用会静默失败(无效果),建议加
assert(!v.empty())或先判大小 - 想填步长非 1 的等差序列?
iota不支持,得手写循环或用std::generate+ lambda
fill 和 iota 在 vector 与原生数组上的调用写法差异
两者都依赖迭代器,但传参方式因类型而异,容易混淆:
立即学习“C++免费学习笔记(深入)”;
-
std::vector<int> v(5);</int>→std::fill(v.begin(), v.end(), 9)或std::iota(v.begin(), v.end(), 100) -
int arr[5];→std::fill(arr, arr+5, 9)或std::iota(arr, arr+5, 100) -
std::array<int> a;</int>→ 必须用a.begin()/a.end(),不能用a;std::fill(a.begin(), a.end(), 9) - 万不得已用
memset?仅限 POD 类型且填 0 或全字节相同值(如memset(arr, 0, sizeof(arr))),其他一律避免
性能与兼容性:C++11 之后哪些写法要特别注意?
fill 和 iota 自 C++98 就存在,但实际使用中几个细节影响跨编译器行为:
- Clang 15+ 对
std::iota在__builtin_assume下可能做激进优化,若起始值来自未初始化变量,结果不可预测 - MSVC 2019 默认开启
/permissive-时,对窄类型(如int8_t*)传入int起始值会警告,建议显式static_cast - 用在 constexpr 上下文?C++20 起
std::fill和std::iota都是constexpr,但必须确保容器本身是字面量类型且生命周期允许(如constexpr std::array) - 批量初始化千万级数组时,
fill和iota性能几乎一致,都是 O(N);真瓶颈往往在内存分配(如vector::resize)而非填充本身
最常被忽略的是:这两个函数都不负责内存分配。传入未分配/未构造的指针,或者对 vector 用了 reserve 却没 resize,就会写到野地址——错误不报在 fill 行,而爆在后续访问时。


















