使用boost::archive反序列化std::string时触发bad allocation异常求助
嘿,我来帮你捋捋这个问题——你遇到的bad_alloc大概率是二进制归档的类型不匹配导致字节读错搞出来的,文本归档没事是因为它的存储方式对类型容错性更高。下面给你具体分析和解决办法:
1. 先修最可能的问题:计数变量的类型不匹配
你保存的时候写的是c.size(),这玩意儿的类型是size_t(标准库容器的size()返回值都是这个),但加载时却用int count来接。在64位系统里,size_t通常是8字节,int只有4字节——这就导致读计数的时候只取了前4字节,剩下的4字节直接被当成第一个std::string的长度值,这个值会大到离谱,直接触发内存分配失败(bad_alloc)。
而文本归档之所以没翻车,是因为它把数字存成文本(比如"3"),读取时会自动解析成正确数值,根本不管底层字节长度是多少。
改法很简单:把加载时的计数变量改成size_t,循环变量也跟着改:
void Load(const std::string& fname, MapType& c) { std::ifstream f(fname.c_str(), std::ios::binary); boost::archive::binary_iarchive ia(f, boost::archive::no_header); size_t count; // 这里换成size_t ia & count; for (size_t i = 0; i < count; ++i) { // 循环变量也用size_t std::string key; ValueType value; ia & key; ia & value; c[key] = value; } }
2. 确认Boost Variant的序列化一致性
虽然你的ValueType是Boost默认支持的类型组合,但二进制归档对类型的序列化要求更严格。你要确保序列化和反序列化时,boost::variant的模板参数顺序完全一致(你这里是bool, int, double, std::string,没问题);如果是跨平台用的话,还要确认字节序一致——不过Boost二进制归档默认会处理字节序,除非你手动改过配置,不然不用太担心。
3. 更省心的方案:直接用Boost自动序列化容器
其实Boost归档本身就支持直接序列化std::map和boost::variant,完全没必要手动逐元素处理,这样能彻底避免手动写代码带来的格式错误。比如把代码简化成这样:
void Save(const std::string& fname, const MapType& c) { std::ofstream f(fname.c_str(), std::ios::binary); boost::archive::binary_oarchive oa(f, boost::archive::no_header); oa & c; // 直接序列化整个map } void Load(const std::string& fname, MapType& c) { std::ifstream f(fname.c_str(), std::ios::binary); boost::archive::binary_iarchive ia(f, boost::archive::no_header); ia & c; // 直接反序列化整个map }
这种方式由Boost内部处理容器大小、元素序列化的所有细节,不仅代码更简洁,还能从根源上避免手动处理的各种坑。
验证步骤
先试试改计数变量的类型,如果问题解决了,那就是这个原因;要是还有问题,直接换成自动序列化整个map的方式,基本就能搞定这类二进制归档的序列化问题了。
内容的提问来源于stack exchange,提问作者racanu

