如何将C风格编译期数组转换为std::array并尽可能减少冗余开销
改造方案说明
C++17及以上版本(最推荐)
C++17引入的类模板实参推导(CTAD) 可以完全省略std::array的模板参数,不需要手动指定数组大小,和原生C数组的写法几乎一致,且完全零开销:
基础数值数组改造示例
#include <array> // 自动推导元素类型为int、大小为5,编译后生成的代码和原生数组完全一致 static constexpr std::array g_numbers{ 1, 2, 3, 4, 5 };
自定义结构体数组改造示例
#include <array> #include <string_view> // 推荐替换裸const char*,编译期可用、无额外开销 // 结构体可命名方便后续复用,也可保留匿名结构 struct CollectionItem { int m_nID; std::string_view m_pszName; }; static constexpr std::array g_collection { CollectionItem{ 1, "Max" }, CollectionItem{ 2, "Fabian" }, CollectionItem{ 3, "Martin" }, // 其余元素直接追加即可,不需要修改模板参数 };
开销说明
std::array是标准规定的聚合类型,内存布局和原生C数组完全一致,没有任何额外成员、虚函数表之类的开销,编译优化后生成的汇编代码和原生数组100%相同,不会有代码膨胀或者运行时性能损失。
另外把static const替换为constexpr可以让数组完全在编译期完成初始化,运行时不需要任何构造逻辑,还能直接参与编译期计算。
C++11/14兼容方案
如果项目暂时无法升级到C++17,可以用辅助模板自动推导大小,避免手动数元素:
#include <array> #include <utility> // 辅助模板,自动推导数组大小和元素类型 template<typename T, typename... Args> constexpr std::array<T, sizeof...(Args)> make_array(Args&&... args) { return { std::forward<Args>(args)... }; } // 使用示例 static const auto g_numbers = make_array<int>(1,2,3,4,5); struct CollectionItem { int m_nID; const char* m_pszName; }; static const auto g_collection = make_array<CollectionItem>( CollectionItem{1, "Max"}, CollectionItem{2, "Fabian"}, CollectionItem{3, "Martin"} );
这种写法也不需要手动指定数组大小,开销和C++17版本完全一致。
改造收益
- 天然携带数组大小信息,调用STL算法或者传递参数时不会出现数组退化为指针丢失长度的问题
- 自带
size()、empty()等工具方法,不需要手动计算数组长度,减少越界风险 - 完全兼容所有原生数组的操作方式,迁移成本极低
内容的提问来源于stack exchange,提问作者Martin Lemburg
相关产品推荐
相关产品推荐

