C++标准库中是否存在与nlohmann json类似的灵活数据结构?
C++标准库中替代nlohmann json的灵活数据结构
C++标准库本身没有直接和nlohmann json完全对等、既支持动态键值对又自带序列化的结构,但可以通过组合现有容器实现类似能力,同时兼顾性能,以下是几种可行方案:
1. std::unordered_map + std::variant(C++17+)
这是最接近nlohmann json使用体验且性能较好的组合:用std::unordered_map存储键值对,std::variant作为值类型,支持容纳多种预定义类型。
#include <unordered_map> #include <variant> #include <string> #include <functional> using Value = std::variant<int, bool, std::string, std::unordered_map<std::string, Value>>; using DynamicObject = std::unordered_map<std::string, Value>; std::string character_new() { DynamicObject obj; obj["level"] = 1; obj["max_hp"] = 2; obj["hp"] = 2; DynamicObject skills; skills["atk"] = 1; skills["dex"] = 1; obj["skills"] = skills; obj["x"] = 1000; obj["y"] = 1000; obj["state"] = -1; obj["map"] = std::string("forest"); obj["dead"] = false; obj["name"] = std::string("Some name"); // 自定义序列化逻辑(递归遍历生成JSON格式) std::function<std::string(const Value&)> serialize = [&](const Value& val) -> std::string { if (std::holds_alternative<int>(val)) { return std::to_string(std::get<int>(val)); } else if (std::holds_alternative<bool>(val)) { return std::get<bool>(val) ? "true" : "false"; } else if (std::holds_alternative<std::string>(val)) { return "\"" + std::get<std::string>(val) + "\""; } else if (std::holds_alternative<DynamicObject>(val)) { const auto& map = std::get<DynamicObject>(val); std::string res = "{"; bool first = true; for (const auto& [key, value] : map) { if (!first) res += ", "; res += "\"" + key + "\": " + serialize(value); first = false; } res += "}"; return res; } return ""; }; return serialize(obj); }
- 优势:
std::unordered_map的存取效率优于nlohmann json的底层结构,std::variant的类型擦除开销极小,整体性能更高。 - 劣势:需要自行实现序列化/反序列化逻辑,访问值时需通过
std::get或std::visit保证类型安全。
2. std::map + std::any(C++17+)
如果需要键有序的动态结构,可以用std::map替代std::unordered_map,搭配std::any实现完全无限制的类型存储:
#include <map> #include <any> #include <string> using DynamicObject = std::map<std::string, std::any>; std::string character_new() { DynamicObject obj; obj["level"] = 1; obj["max_hp"] = 2; // 其余字段赋值逻辑类似... // 序列化需自行实现,访问值时用std::any_cast,如: // int level = std::any_cast<int>(obj["level"]); return ""; // 替换为自定义序列化结果 }
- 优势:能容纳任意类型,键天然有序。
- 劣势:
std::any的类型擦除开销比std::variant大,性能较差;类型转换时若类型不匹配会抛出异常,类型安全性弱。
3. 结构体 + 轻量序列化库(折中方案)
如果你的数据结构实际是固定的(比如示例中的角色属性),只是习惯了动态写法,更推荐用结构体配合轻量序列化库:
#include <string> #include <unordered_map> struct Character { int level = 1; int max_hp = 2; int hp = 2; std::unordered_map<std::string, int> skills{{"atk", 1}, {"dex", 1}}; int x = 1000; int y = 1000; int state = -1; std::string map; bool dead = false; std::string name = "Some name"; }; // 用序列化库生成JSON或二进制格式(如flatbuffers、protobuf)
- 优势:类型安全,性能远高于动态结构,序列化效率极高。
- 劣势:无法在运行时动态添加新字段,结构需提前定义。
总结
- 必须保留运行时动态添加键值对的灵活性:优先选
std::unordered_map<std::string, std::variant<...>>,性能优于nlohmann json。 - 可接受提前定义结构:用结构体+轻量序列化库,是性能最优的选择。
- 非必要不要用
std::any,它的性能和类型安全性都不如std::variant。
内容的提问来源于stack exchange,提问作者user19816087
相关产品推荐
相关产品推荐

