使用 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

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐