Search code examples
c++nlohmann-json

Strange behaviour when using nlohmann-json


I have the following function:

// get-function that can handle nullptr.
template <typename T>
static const T get(const nlohmann::json& json, const T& retOnNull = T())
{
    return json.is_null() ? retOnNull : json.get<T>();
}

Then I call it like this:

nlohmann::json j;

// ...
// Load json from file into j

auto ret = get<std::string>(j["SomeKey"], "");

Now I would expect one of three things to happen:

  1. If "SomeKey" exists and is a string it should return that value
  2. If "SomeKey" doesn't exist it should first be created with null as default value and then sent into the function which should return an empty string as it received a null value
  3. If "SomeKey" existed but wasn't a string it should throw a json.exception.type_error.302

Instead I sometimes (randomly) get the json.exception.type_error.302 exception even though, in my case, "SomeKey" doesn't exist. I checked what happens at that point and the data sent into the get function seems to be not null and of type 105 (which is an indication the data is undefined). So how can this call into this function yield undefined data? Is it something about the new json entry going out of scope due to the reference pointer? Why does it happen randomly and not consistently? Is this an invalid way of using a new key?


Solution

  • The code is invoking undefined behavior: https://json.nlohmann.me/api/basic_json/operator%5B%5D/#template-parameters

    If the element with key key does not exist, the behavior is undefined and is guarded by a runtime assertion!

    Use json::at() instead so you get a proper error (by exception) when the key doesn't exist or a type mismatch was detected.

    Alternatively, use json::contains() to check if the key is legal to access before attempting to access it: https://json.nlohmann.me/api/basic_json/contains/

    If j.contains(x) returns true for a key or JSON pointer x, then it is safe to call j[x].