You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中请求非const所有者修改const nlohmann::json键值的可行性

结论

该需求完全可以实现,不存在本质技术障碍,核心是先定位传入const子节点在根json对象中的位置,完成自定义合法性校验后,通过所有者持有的非const根对象完成修改即可。

实现思路

实现只需要解决三个核心问题:

  • 校验传入的const子节点确实归属于待修改的根json对象,拦截外部传入无关json引用的非法修改请求
  • 定位该子节点在根json中的访问路径
  • 完成自定义合法性校验后,通过所有者持有的非const根对象修改对应路径的值

nlohmann::json原生支持RFC 6901定义的JSON Pointer规范,可以通过标准化路径直接定位到任意层级的子节点。我们只需要提前递归遍历根对象,通过内存地址匹配找到传入子节点对应的路径即可,全程不需要依赖危险的未定义操作。

完整可运行示例
#include <nlohmann/json.hpp>
#include <iostream>
#include <optional>
#include <fstream>

using json = nlohmann::json;

// 辅助函数:递归查找目标const节点在根节点下对应的JSON Pointer
std::optional<json::json_pointer> find_node_path(const json& root, const json& target) {
    // 匹配到当前节点就是目标,返回空路径(对应根节点自身)
    if (&root == &target) {
        return json::json_pointer{};
    }

    // 对象类型遍历所有键递归查找
    if (root.is_object()) {
        for (auto& [key, val] : root.items()) {
            auto sub_path = find_node_path(val, target);
            if (sub_path.has_value()) {
                return sub_path.value().push_front(key);
            }
        }
    }
    // 数组类型遍历所有索引递归查找
    else if (root.is_array()) {
        for (size_t i = 0; i < root.size(); ++i) {
            auto sub_path = find_node_path(root[i], target);
            if (sub_path.has_value()) {
                return sub_path.value().push_front(i);
            }
        }
    }

    // 未找到目标节点返回空
    return std::nullopt;
}

// 目标修改请求函数
template<typename T>
bool RequestDataChange(json& root, const json& target_node, T new_val) {
    // 第一步:校验目标节点归属,拒绝不属于当前根对象的修改请求
    auto path = find_node_path(root, target_node);
    if (!path.has_value()) {
        std::cerr << "非法修改请求:目标节点不属于当前json对象" << std::endl;
        return false;
    }

    // 第二步:自定义合法性校验逻辑,可根据业务需求调整规则
    // 示例规则:仅允许修改根节点下的SomeKey字段
    if (path.value().to_string() != "/SomeKey") {
        std::cerr << "校验失败:该路径无修改权限" << std::endl;
        return false;
    }

    // 第三步:校验通过,通过非const根对象和路径直接修改值
    root[path.value()] = new_val;
    return true;
}

int main() {
    // 对应原示例中从文件加载json的逻辑
    std::ifstream json_file("someJsonFile.json");
    json j = json::parse(json_file);

    const json& constJsonRef = j;

    // 发起修改请求
    bool ret = RequestDataChange(j, constJsonRef["SomeKey"], 6);
    if (ret) {
        std::cout << "修改成功,修改后j的值为:" << j.dump(2) << std::endl;
    }

    // 非法路径的修改请求会被直接拦截
    ret = RequestDataChange(j, constJsonRef["OtherKey"], "invalid_val");
    if (!ret) {
        std::cout << "非法修改请求已被拦截" << std::endl;
    }

    return 0;
}
注意事项
  • 递归查找路径的时间复杂度和json节点总数正相关,如果你的json结构体量极大、修改请求触发频率很高,可以提前缓存所有节点地址和对应路径的映射,降低性能开销
  • 不要直接对传入的const子节点用const_cast转非const后修改,必须先完成节点归属校验,否则如果外部传入的是其他const json对象的引用,强制转非const修改会触发未定义行为
  • 如果你的业务场景允许调用方直接传JSON Pointer字符串(比如"/SomeKey")而非子节点引用,可以直接省掉递归查找路径的步骤,执行效率会更高

内容的提问来源于stack exchange,提问作者Omer Kawaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 02:12:35