如何用std::array替代std::unordered_map并逐个填充指定元素?
用std::array替代std::unordered_map优化枚举键值访问性能
问题背景
我原本用std::unordered_map存储枚举与纹理数据的映射,但这个map被数千次访问,性能开销占所在函数运行时间的20%。考虑到枚举值可以直接作为数组索引,想换成std::array来提升性能,但填充数组时遇到了"incomplete"错误。需要注意的是,并非所有枚举值都需要对应纹理对象,未设置的元素可以为nullptr,希望能逐个定义数组中的值。
原实现代码
Block.h
enum class BlockType : uint8_t { BlockType_Air = 0, BlockType_Default = 1, BlockType_Grass = 2, BlockCount }; struct BlockTextureData { std::string top; std::string bottom; std::string left; std::string right; std::string front; std::string back; }; extern std::unordered_map<BlockType, BlockTextureData*> BlockTextures;
Block.cpp
std::unordered_map<BlockType, BlockTextureData*> BlockTextures = { {BlockType::BlockType_Default, new BlockTextureData{"UV","UV","UV","UV","UV", "UV"}}, {BlockType::BlockType_Grass, new BlockTextureData{"GrassTop","GrassBottom","GrassSide","GrassSide","GrassSide", "GrassSide"}} };
错误的尝试代码
Block.h
extern std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures;
Block.cpp
std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures[static_cast<size_t>(BlockType::BlockType_Default)] = new BlockTextureData{"UV","UV","UV","UV","UV", "UV"}; std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures[static_cast<size_t>(BlockType::BlockType_Grass)] = new BlockTextureData{"GrassTop","GrassBottom","GrassSide","GrassSide","GrassSide", "GrassSide"};
正确的实现方式
你的错误在于重复定义了BlockTextures,并且错误地将数组当作二维数组来赋值。正确的做法是先创建一个大小为BlockCount的数组,默认初始化所有元素为nullptr,再通过枚举值转换的索引逐个赋值。
修正后的代码
Block.h
#include <array> #include <string> enum class BlockType : uint8_t { BlockType_Air = 0, BlockType_Default = 1, BlockType_Grass = 2, BlockCount }; struct BlockTextureData { std::string top; std::string bottom; std::string left; std::string right; std::string front; std::string back; }; // 声明全局数组,大小由枚举值BlockCount确定 extern std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures;
Block.cpp
#include "Block.h" #include <array> // 初始化数组,所有元素默认值为nullptr std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures{}; // 初始化需要的元素,可放在初始化函数中 void initBlockTextures() { // 将枚举值转为size_t作为数组索引 auto defaultIdx = static_cast<size_t>(BlockType::BlockType_Default); BlockTextures[defaultIdx] = new BlockTextureData{"UV","UV","UV","UV","UV", "UV"}; auto grassIdx = static_cast<size_t>(BlockType::BlockType_Grass); BlockTextures[grassIdx] = new BlockTextureData{"GrassTop","GrassBottom","GrassSide","GrassSide","GrassSide", "GrassSide"}; } // 确保初始化函数在程序启动时执行(比如用全局初始化器) namespace { struct Initializer { Initializer() { initBlockTextures(); } } init; }
补充说明
- 内存管理:如果使用
new创建BlockTextureData对象,记得在程序退出时遍历数组,对非nullptr的元素执行delete,避免内存泄漏。 - 访问方式:后续访问时直接用
BlockTextures[static_cast<size_t>(BlockType::XXX)]即可,比unordered_map的查找快得多。
内容的提问来源于stack exchange,提问作者Marko Taht
相关产品推荐
相关产品推荐

