使用 nlohmann::json 的常见错误与最佳实践(含 value() 崩溃原因解析)
使用 nlohmann::json 的常见错误与最佳实践(含 value() 崩溃原因解析)
nlohmann::json 是 C++ 中最流行、最轻量的 JSON 库,语法类似 JavaScript,使用方便。但如果不理解其行为方式,常常会遇到异常崩溃。本文将介绍:
JSON 常见取值方法
为什么 value() 会抛异常
如何写出更安全不崩溃的代码
推荐的 JSON 读取模板
本文所有内容都基于实际项目经验,适合新手与工程开发者。
1️⃣ JSON 最常用的操作方式
1. 判断字段是否存在
if (j.contains(“type”)) {
std::string type = j[“type”];
}
2. 使用 value() 提供默认值(推荐)
std::string type = j.value(“type”, “”);
当字段不存在时,不会抛异常,而是返回默认值。
2️⃣ 常见错误:value() 崩溃
遇到的错误:
json.exception.type_error.306] cannot use value() with null
表示 JSON 本身是 null,而不是缺字段
例如:
nlohmann::json j;
std::string type = j.value(“type”, “”); // ❌ j 是 null → 崩溃
也会在这样写时出现:
worker.push(&device, &j {
std::string type = j.value(“type”, “”); // j 已经被释放/失效
});
问题来自 引用引用失效(捕获了一个不再存在的 j)。
3️⃣ 如何写出不崩溃的 JSON 读取代码
✔ 正确写法 1:先确保 j 不是 null
if (j.is_null()) {
// 无效的 JSON
return;
}
std::string type = j.value(“type”, “”);
✔ 正确写法 2:不要捕获引用(极强推荐)
错误写法(之前的代码):
worker.push(&device, &j {
std::string type = j.value(“type”, “”);
});
如果 j 离开作用域,会变成悬空引用 → 崩溃。
正确写法:
worker.push(device, j {
std::string type = j.value(“type”, “”);
});
捕获 j 的副本可以保证生命周期完整,不会悬空。
✔ 正确写法 3:读取前判断类型
if (j.contains(“type”) && j[“type”].is_string()) {
type = j[“type”];
}
4️⃣ JSON 读取安全模板(强烈建议使用)
下面是一段 “不会崩溃” 的万能读取代码:
std::string safe_get_string(const nlohmann::json& j,
const std::string& key,
const std::string& def = “”)
{
if (!j.is_object()) return def;
if (!j.contains(key)) return def;
if (!j[key].is_string()) return def;
return j[key].getstd::string();
}
使用方式:
std::string type = safe_get_string(j, “type”);
无论 j 是空、null、格式错误,都不会崩溃。
5️⃣ 常见陷阱大全(建议收藏)
场景 会不会崩溃? 原因
j[“a”] 可能崩溃 如果 a 存在但类型不对
j.value(“a”, “”) 会崩溃 如果 j 本身是 null
j[“a”].getstd::string() 可能崩溃 a 不是字符串
捕获 &j 放进线程 必崩溃 j 会被释放
捕获 j(值复制) 不会崩溃 生命周期独立
6️⃣ 最推荐的写法(简洁 + 安全 + 不崩)
worker.push(j, &device {
std::string type = j.value(“type”, “”);
if (type == "auto") {
device.enableAuto();
}
});
注意:
捕获 j 是值传递,不会用到悬空引用
value(“type”, “”) 方便安全
就算没有 “type”,程序也不会退出
🎉 总结
判断字段 j.contains(“type”)
安全读取 j.value(“type”, “”)
防止空 JSON if (j.is_null())
避免线程崩溃 不要用引用捕获 j
最强安全读取 自己封装 safe_get_string
更多推荐



所有评论(0)