如何高效运用_fill与iota技巧批量初始化数组?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1224个文字,预计阅读时间需要5分钟。
codestd::fill 是最直接的全设置为某值的方案,但它不检查容器是否为空,也不验证迭代器是否合法——错误。begin 和 end 会直接导致未定义行为——错误。
- 对
std::vector:确保用v.begin()和v.end(),别手抖写成v.begin() + 1或漏掉+ v.size() - 对原生数组:必须显式计算地址边界,
int arr[10]; std::fill(arr, arr + 10, 42);—— 写成arr + 11就越界了 - 对
std::array:推荐用a.begin()/a.end(),比&a[0]更安全,尤其在模板上下文中 - 性能上,
std::fill通常被编译器优化为memset(仅限 trivial 类型且值为 0),但非零值或自定义类型仍走循环赋值
用 std::iota 填递增序列,注意起始值和类型匹配
std::iota 生成等差为 1 的整数序列,但它不关心目标容器元素类型能否隐式转换——若起始值是 int 而容器是 unsigned char,溢出后行为由实现定义,不是截断就是未定义。
- 常见错误:
unsigned char buf[5]; std::iota(buf, buf + 5, 250);→ 第二个元素就溢出,结果不可预测 - 安全做法:起始值类型应与容器元素类型一致,或至少能无损表示整个序列范围,例如
std::iota(v.begin(), v.end(), 0LL)配std::vector<long long></long> - 不能用于浮点数组(标准未定义行为),想填
0.5, 1.5, 2.5...得自己写循环或用std::transform+ lambda - 它只支持等差为 1;要等差为 2 或带偏移,得组合
std::generate,别硬套iota
原生数组初始化时,{} 初始化和 std::fill 的取舍
声明时用 int a[100]{}; 是零初始化,快且安全;但运行时动态赋值只能靠 std::fill 或循环。这两者不是替代关系,而是阶段不同。
-
int a[100] = {0};:只在定义时生效,后续修改无效;且{0}并非“全设 0”,而是首元素为 0、其余按默认初始化(对int也是 0,但对类类型可能调用默认构造) -
int a[100]; std::fill(std::begin(a), std::end(a), 7);:运行时可控,适合复用同一块内存多次重置 - 注意
std::begin(a)在 C++11+ 才可靠支持原生数组;C++98 中必须手写a和a + N,否则编译失败 - 若数组很大(如 MB 级),
std::fill可能不如memset快(尤其填 0),但memset仅适用于字节可拷贝类型,且值必须是单字节重复(即只能填 0、-1 等)
自定义类型数组初始化,std::fill 和 std::iota 都受限
std::fill 要求类型可拷贝/移动,std::iota 则根本不能用于非整型——遇到 std::string 或自定义结构体,这两个函数基本失效。
立即学习“C++免费学习笔记(深入)”;
- 填相同对象:
std::vector<:string> v(100, "hello");</:string>构造时指定初值最高效;运行时重填用v.assign(100, "hello"),比fill更明确且避免迭代器误用 - 填序号字符串(如
"item_0","item_1"):必须用std::generate:std::generate(v.begin(), v.end(), [n = 0]() mutable { return "item_" + std::to_string(n++); }); - 若类型无默认构造(如含
const成员),std::array<t n></t>声明即需显式初始化,{}不够用,得写{{{...}}}或用聚合初始化语法 - 别试图对
std::vector用iota填索引——v[i] = i比std::iota(v.begin(), v.end(), 0)多一次间接访问,但语义清晰、无类型陷阱
本文共计1224个文字,预计阅读时间需要5分钟。
codestd::fill 是最直接的全设置为某值的方案,但它不检查容器是否为空,也不验证迭代器是否合法——错误。begin 和 end 会直接导致未定义行为——错误。
- 对
std::vector:确保用v.begin()和v.end(),别手抖写成v.begin() + 1或漏掉+ v.size() - 对原生数组:必须显式计算地址边界,
int arr[10]; std::fill(arr, arr + 10, 42);—— 写成arr + 11就越界了 - 对
std::array:推荐用a.begin()/a.end(),比&a[0]更安全,尤其在模板上下文中 - 性能上,
std::fill通常被编译器优化为memset(仅限 trivial 类型且值为 0),但非零值或自定义类型仍走循环赋值
用 std::iota 填递增序列,注意起始值和类型匹配
std::iota 生成等差为 1 的整数序列,但它不关心目标容器元素类型能否隐式转换——若起始值是 int 而容器是 unsigned char,溢出后行为由实现定义,不是截断就是未定义。
- 常见错误:
unsigned char buf[5]; std::iota(buf, buf + 5, 250);→ 第二个元素就溢出,结果不可预测 - 安全做法:起始值类型应与容器元素类型一致,或至少能无损表示整个序列范围,例如
std::iota(v.begin(), v.end(), 0LL)配std::vector<long long></long> - 不能用于浮点数组(标准未定义行为),想填
0.5, 1.5, 2.5...得自己写循环或用std::transform+ lambda - 它只支持等差为 1;要等差为 2 或带偏移,得组合
std::generate,别硬套iota
原生数组初始化时,{} 初始化和 std::fill 的取舍
声明时用 int a[100]{}; 是零初始化,快且安全;但运行时动态赋值只能靠 std::fill 或循环。这两者不是替代关系,而是阶段不同。
-
int a[100] = {0};:只在定义时生效,后续修改无效;且{0}并非“全设 0”,而是首元素为 0、其余按默认初始化(对int也是 0,但对类类型可能调用默认构造) -
int a[100]; std::fill(std::begin(a), std::end(a), 7);:运行时可控,适合复用同一块内存多次重置 - 注意
std::begin(a)在 C++11+ 才可靠支持原生数组;C++98 中必须手写a和a + N,否则编译失败 - 若数组很大(如 MB 级),
std::fill可能不如memset快(尤其填 0),但memset仅适用于字节可拷贝类型,且值必须是单字节重复(即只能填 0、-1 等)
自定义类型数组初始化,std::fill 和 std::iota 都受限
std::fill 要求类型可拷贝/移动,std::iota 则根本不能用于非整型——遇到 std::string 或自定义结构体,这两个函数基本失效。
立即学习“C++免费学习笔记(深入)”;
- 填相同对象:
std::vector<:string> v(100, "hello");</:string>构造时指定初值最高效;运行时重填用v.assign(100, "hello"),比fill更明确且避免迭代器误用 - 填序号字符串(如
"item_0","item_1"):必须用std::generate:std::generate(v.begin(), v.end(), [n = 0]() mutable { return "item_" + std::to_string(n++); }); - 若类型无默认构造(如含
const成员),std::array<t n></t>声明即需显式初始化,{}不够用,得写{{{...}}}或用聚合初始化语法 - 别试图对
std::vector用iota填索引——v[i] = i比std::iota(v.begin(), v.end(), 0)多一次间接访问,但语义清晰、无类型陷阱

