应使用 Json::CharReaderBuilder 构造解析器并检查 parseFromStream 返回值,错误时通过 errs 获取详细信息,避免直接访问未成功解析的空对象。
JsonCpp 不自带解析器,得手动构造 Json::CharReaderBuilder 或用旧版 Json::Reader。新版推荐前者,更安全、支持 Unicode。
常见错误是直接传 raw string 给 parse() 却忽略返回值,导致解析失败却继续访问空对象:
Json::Value root;
Json::CharReaderBuilder builder;
std::string errs;
std::istringstream ss("{\"name\":\"alice\",\"age\":30}");
if (!Json::parseFromStream(builder, ss, &root, &errs)) {
// 必须检查!errs 里有具体错误位置和原因
std::cerr << "JSON parse error: " << errs << std::endl;
return;
}Json::CharReaderBuilder 默认启用 strictMode,不接受 trailing comma、单引号、注释等非标准写法Json::Reader(已弃用),它在 v1.9+ 中被标记为 deprecated,且线程不安全直接链式调用 root["data"]["items"][0]["id"] 很危险——任一中间层缺失都会返回空 Json::Value,但 asInt() 或 asString() 在空值上调用会抛 std::logic_error。
正确做法是逐层检查 isNull() 和 isMember(),或用带默认值的 get():
// 安全写法:提供默认值,类型自动转换
int id = root.get("data", Json::Value::nullRef)
.get("items", Json::Value::nullRef)
.get(0, Json::Value::nullRef)
.get("id", Json::Value(0)).asInt();
// 或更清晰的判断
if (root.isObject() &&
root.isMember("user") &&
root["user"].isObject() &&
root["user"].isMember("email")) {
std::string email = root["user"]["email"].asString();
}
Json::Value::nullRef 是轻量占位符,比构造新 Json::Value() 更高效get(key, defaultValue) 的 defaultValue 类型必须和期望访问类型兼容,否则可能静默转成 0 或空串array[100] 返回空值,务必先用 array.size() 判断输出控制权在 Json::StreamWriterBuilder,不是简单调 toString() 就完事。默认格式是紧凑型(无换行缩进),调试时很难看。
Json::StreamWriterBuilder builder; builder["indentation"] = " "; // 注意:必须是字符串,不能是 \t builder["commentStyle"] = "None"; // 禁用注释(默认可能加 /* ... */) std::string json_str = Json::writeString(builder, root);
builder["indentation"] = "" 回到紧凑模式root.toStyledString() 是快捷方式,但无法定制,且内部固定用 4 空格缩进、启用注释,不适合生产环境Json::Value,JsonCpp 不提供 setPrecision()
JsonCpp 编译后分静态库 jsoncpp 和头文件两部分,CMake 项目常只 link 库却忘了 include 目录,报 Json/json.h: No such file。
CMakeLists.txt 正确写法示例:
find_package(jsoncpp REQUIRED)
target_link_libraries(myapp PRIVATE jsoncpp_lib)
target_include_directories(myapp PRIVATE ${jsoncpp_INCLUDE_DIRS})libjsoncpp-dev,但头文件路径是 /usr/include/jsoncpp/json/json.h,所以 include 时得写 #include ,不是
jsoncpp,但生成的库名可能是 jsoncpp.lib 或 jsoncpp_static.lib,取决于是否开启 JSONCPP_LIB_BUILD_SHARED
LogicError 在 Release 可能变成静默错误或崩溃最常被跳过的一步:没验证输入 JSON 是否合法就直接 parse,结果程序在用户上传的畸形数据上当场退出。解析前加个 std::string::find_first_not_of(" \t\r\n") != std::string::npos 至少能防空输入。