使用cereal库解析JSON时触发rapidjson IsArray断言失败错误怎么办?
使用cereal解析JSON时出现
IsArray()断言错误的解决办法 问题场景
编写小游戏代码时,用cereal库读取JSON作为玩家配置,简化后的示例代码运行报错,错误提示Error deserializing JSON: rapidjson internal assertion failure: IsArray()。
示例C++代码
#include <cereal/types/map.hpp> #include <cereal/types/string.hpp> #include <cereal/archives/json.hpp> #include <string> #include <map> #include <iostream> #include <fstream> struct Item { std::string name; int number; template <class Archive> void serialize(Archive &ar) { ar(cereal::make_nvp("name", name), cereal::make_nvp("number", number)); } }; int main() { std::map<std::string, Item> items; std::ifstream file("dataForTesting.json"); if (!file.is_open()) { std::cerr << "Could not open the file!" << std::endl; return 1; } try { cereal::JSONInputArchive archive(file); archive(items); } catch (const cereal::Exception& e) { std::cerr << "Error deserializing JSON: " << e.what() << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "An error occurred: " << e.what() << std::endl; return 1; } for (const auto& item : items) { std::cout << "Item ID: " << item.first << "\nName: " << item.second.name << "\nNumber: " << item.second.number << "\n" << std::endl; } return 0; }
对应的JSON文件(dataForTesting.json)
{ "item1": { "name": "Item One", "number": 1 }, "item2": { "name": "Item Two", "number": 2 }, "item3": { "name": "Item Three", "number": 3 } }
编译与执行命令
c++ testingTesting.c++ -o test -std=c++11 -I. ./test
错误信息
Error deserializing JSON: rapidjson internal assertion failure: IsArray()
核心原因与解决办法
cereal默认要求std::map对应的JSON是数组形式的键值对集合,而不是直接的对象嵌套。以下三种方案任选其一即可解决:
方案1:修改JSON为数组结构
把原JSON改成数组格式,每个元素包含key和value字段:
[ { "key": "item1", "value": { "name": "Item One", "number": 1 } }, { "key": "item2", "value": { "name": "Item Two", "number": 2 } }, { "key": "item3", "value": { "name": "Item Three", "number": 3 } } ]
方案2:给map套一层结构体(无需修改JSON)
在代码中给std::map包装一个结构体,让cereal识别外层对象:
struct ItemMap { std::map<std::string, Item> items; template <class Archive> void serialize(Archive &ar) { ar(items); } };
同时修改main函数中的逻辑:
int main() { ItemMap itemMap; std::ifstream file("dataForTesting.json"); if (!file.is_open()) { std::cerr << "Could not open the file!" << std::endl; return 1; } try { cereal::JSONInputArchive archive(file); archive(itemMap); for (const auto& item : itemMap.items) { std::cout << "Item ID: " << item.first << "\nName: " << item.second.name << "\nNumber: " << item.second.number << "\n" << std::endl; } } catch (const cereal::Exception& e) { std::cerr << "Error deserializing JSON: " << e.what() << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "An error occurred: " << e.what() << std::endl; return 1; } return 0; }
方案3:给map指定顶层键名(需修改JSON)
修改JSON,把整个map放在一个顶层键下:
{ "items": { "item1": { "name": "Item One", "number": 1 }, "item2": { "name": "Item Two", "number": 2 }, "item3": { "name": "Item Three", "number": 3 } } }
然后修改反序列化代码,用make_nvp指定键名:
archive(cereal::make_nvp("items", items));
内容的提问来源于stack exchange,提问作者mroowak
相关产品推荐
相关产品推荐

