static std::unordered_multimap栈溢出:如何直接在堆初始化大量元素
嘿,这个问题我之前碰到过类似的——VS对栈大小的限制确实很严格,尤其是当你用超大的initializer_list初始化容器时,编译器会把所有临时元素先塞栈里,直接爆栈。不过不用慌,咱们不用大改那1225条指令的代码,就能轻松解决:
实用解决方案
方案1:改用静态数组作为数据源(改动最小)
你现在的代码大概是这样的:
static const std::unordered_multimap<std::string, ASM_INSTRUCTION> instr_map = { {"MOV", { ... }}, {"ADD", { ... }}, // 1225条指令... };
只需要把原来的大括号内容移到一个静态数组里(静态数组存在全局/静态存储区,完全不占栈空间),再用范围构造函数初始化容器:
// 把所有指令条目原封不动搬到这个静态数组里 static const std::pair<std::string, ASM_INSTRUCTION> instr_entries[] = { {"MOV", { ... }}, {"ADD", { ... }}, // 1225条指令,不用改任何内容 }; // 用数组的首尾迭代器构造unordered_multimap static const std::unordered_multimap<std::string, ASM_INSTRUCTION> instr_map( std::begin(instr_entries), std::end(instr_entries) );
这个方案几乎零修改:只是把初始化列表的内容挪到了数组里,编译器会把数组放在静态存储区,构造容器时直接从这里读取元素,彻底避开栈溢出问题。
方案2:懒加载+堆上临时容器(适合不想加全局数组的场景)
如果不想单独定义数组,可以借助lambda和静态局部变量的懒加载特性,让初始化数据在堆上生成:
// 封装成一个获取函数 static const std::unordered_multimap<std::string, ASM_INSTRUCTION>& get_instr_map() { // static局部变量只会初始化一次,且C++11后线程安全 static const auto map = []{ // 这里的vector在堆上分配内存,不会占用栈空间 std::vector<std::pair<std::string, ASM_INSTRUCTION>> temp_entries = { {"MOV", { ... }}, {"ADD", { ... }}, // 原有的1225条指令直接复制过来 }; // 用vector构造unordered_multimap return std::unordered_multimap<std::string, ASM_INSTRUCTION>( temp_entries.begin(), temp_entries.end() ); }(); return map; }
之后你原来使用instr_map的地方,改成调用get_instr_map()就行。这个方案不用额外定义全局数组,还能实现延迟初始化,第一次用到时才会构造容器。
为什么原来的写法会触发栈溢出?
当你用大括号直接初始化unordered_multimap时,编译器会把所有std::pair<std::string, ASM_INSTRUCTION>临时对象先放到栈上的一个临时数组里,再把这个数组的指针传给initializer_list的构造函数。1225个元素加起来占用近100KB,远超VS默认的16KB栈上限,自然就触发了溢出警告。
上面两个方案都是把初始化数据放到栈以外的区域(静态存储区或堆),完全不需要修改你的ASM_INSTRUCTION结构体或者指令条目内容,改动极小。
内容的提问来源于stack exchange,提问作者E. H
相关产品推荐
相关产品推荐

