首页
/ JSON for Modern C++ 深度解析:nlohmann::basic_json::clear() 的类型保持语义与源码实现

JSON for Modern C++ 深度解析:nlohmann::basic_json::clear() 的类型保持语义与源码实现

2026-09-05 19:59:52作者:胡唯隽

clear() 是 JSON for Modern C++(nlohmann/json,仓库内源码标注版本 3.12.0)中 nlohmann::basic_json 类的一个修改器(modifier)成员函数,它清空 JSON 值的内容但保留其类型。读完本篇,你可以准确掌握 clear() 对七种 JSON 值类型各自的重置结果、异常与复杂度保证,以及迭代器失效规则,并能在 include/nlohmann/json.hpp 的源码实现层面理解每种类型对应的底层清理动作。

函数签名与核心语义

官方 API 文档(docs/mkdocs/docs/api/basic_json/clear.md)给出的签名为:

void clear() noexcept;

其语义可以概括为:清空 JSON 值的内容,并将其重置为该类型对应的“默认值”,效果等价于:

*this = basic_json(type());

也就是说,clear() 调用后值仍然保持调用前的类型(通过 type() 返回的值),但内容被换成 basic_json(value_t) 构造函数为该类型生成的初始值。这是它与 std::vector::clear() 等容器清空操作的共同点,但由于 basic_json 是多态容器(一个变量可以是 object、array、string、number 等任意类型),需要逐类型定义“空”的含义。

各类型 clear() 之后的初始值

文档给出的完整类型—初始值对照表如下:

值类型(value_t) clear() 之后的初始值
null null
boolean false
string ""
number(整数/无符号/浮点) 0 / 0 / 0.0
binary 空字节序列(empty byte vector)
object {}
array []

需要注意两个细微之处:

  • 文档表中 number 统一写作 0,但源码实现区分了 number_integer(置 0)、number_unsigned(置 0)和 number_float(置 0.0)三种内部子类型,序列化时整数输出 0、浮点输出 0.0
  • binary 类型清空后是空的字节容器,但仍保持 binary 类型——由于空二进制没有“非空”可言,empty() 对清空后的 binary 返回 false(测试用例中显式用 CHECK(!j.empty()) 验证了这一点,见后文测试小节)。

完整可运行示例与输出

官方文档内置的示例(源文件 clear.cpp)演示了 clear() 对不同 JSON 类型的作用,完整代码如下:

#include <iostream>
#include <nlohmann/json.hpp>

using json = nlohmann::json;

int main()
{
    // create JSON values
    json j_null;
    json j_boolean = true;
    json j_number_integer = 17;
    json j_number_float = 23.42;
    json j_object = {{"one", 1}, {"two", 2}};
    json j_array = {1, 2, 4, 8, 16};
    json j_string = "Hello, world";

    // call clear()
    j_null.clear();
    j_boolean.clear();
    j_number_integer.clear();
    j_number_float.clear();
    j_object.clear();
    j_array.clear();
    j_string.clear();

    // serialize the cleared values()
    std::cout << j_null << '\n';
    std::cout << j_boolean << '\n';
    std::cout << j_number_integer << '\n';
    std::cout << j_number_float << '\n';
    std::cout << j_object << '\n';
    std::cout << j_array << '\n';
    std::cout << j_string << '\n';
}

运行输出(与 clear.output 一致):

null
false
0
0.0
{}
[]
""

可以看到:对象清空后是 {}、数组清空后是 []、字符串清空后是 ""、整数清空后是 0、浮点清空后是 0.0——类型全部保持不变,只有内容归零。

源码实现:按类型分发的清空逻辑

clear() 的实现位于单头文件 single_include/nlohmann/json.hpp(拆分源码中为 include/nlohmann/json.hpp),核心是一个按内部类型标签 m_data.m_type 分发的 switch 语句:

void clear() noexcept
{
    switch (m_data.m_type)
    {
        case value_t::number_integer:
        {
            m_data.m_value.number_integer = 0;
            break;
        }

        case value_t::number_unsigned:
        {
            m_data.m_value.number_unsigned = 0;
            break;
        }

        case value_t::number_float:
        {
            m_data.m_value.number_float = 0.0;
            break;
        }

        case value_t::boolean:
        {
            m_data.m_value.boolean = false;
            break;
        }

        case value_t::string:
        {
            m_data.m_value.string->clear();
            break;
        }

        case value_t::binary:
        {
            m_data.m_value.binary->clear();
            break;
        }

        case value_t::array:
        {
            m_data.m_value.array->clear();
            break;
        }

        case value_t::object:
        {
            m_data.m_value.object->clear();
            break;
        }

        case value_t::null:
        case value_t::discarded:
        default:
            break;
    }
}

从源码结构可以读出几条实现层面的信息:

  1. 标量类型直接赋值number_integernumber_unsignednumber_floatboolean 都是值语义成员,清空就是写入零值/false,不经过任何动态内存操作,因此可以做到 noexcept
  2. 容器类型委托给 C++ 标准容器的 clear()stringbinaryarrayobject 底层分别是 string_tbinary_tarray_tobject_t 成员,clear() 直接委托给它们的 clear() 方法释放元素;
  3. nulldiscarded 是空操作null 本就无内容;discarded(解析错误时出现的“被丢弃的值”)同样保持原样。这正是实现 *this = basic_json(type()) 等价语义的具体展开——库没有真正调用一次拷贝赋值,而是用分支赋值获得了更低开销的等价效果;
  4. binary 只清空字节、不清除 subtypem_data.m_value.binary->clear() 作用于底层容器 byte_container_with_subtype(见 include/nlohmann/byte_container_with_subtype.hpp)。从源码结构看,该类的 clear() 继承自 BinaryType(默认 std::vector<std::uint8_t>),只会清空字节序列,而 m_subtype/m_has_subtype 成员并不随之重置;如果还需要去掉二进制子类型,应另行调用 clear_subtype()

异常安全、复杂度与迭代器失效

官方文档明确给出了三点契约:

  • 异常安全:No-throw guarantee——clear() 永不抛出异常(与 noexcept 标注一致);
  • 复杂度:与 JSON 值的大小成线性关系。对字符串/数组/对象而言,线性开销来自逐个销毁容器元素(如对象的键值对、数组的元素),而标量类型是常数时间的赋值;
  • 注意事项:所有与此容器相关的迭代器、指针和引用都会在 clear() 之后失效。由于 basic_json 的迭代器会解引用出内嵌子 JSON 值(例如 operator* 返回 const_reference),清空后任何持有迭代器或 get_ptr/引用绑定旧元素的代码都必须丢弃。

单元测试:逐类型验证“值 == 同类型空值”

测试文件 tests/src/unit-modifiers.cppclear() SECTION 对每种类型都做了结构化断言,其验证模式高度一致:

SECTION("string")
{
    json j = "hello world";
    json const k = j;

    j.clear();
    CHECK(j == json(json::value_t::string));  // 内容等于“空字符串”
    CHECK(j == json(k.type()));               // 等于以原类型构造的默认值
}

即断言两条:其一,清空后的值等于用 value_t 标签构造的同类型默认值(json(json::value_t::string) 就是 "");其二,值等于 json(k.type()),其中 k 是清空前保存的副本——这正好从行为层面验证了文档中“等价于 *this = basic_json(type())”的语义描述。测试覆盖了 boolean、string、array(空/非空)、object(空/非空)、binary(空/非空)、number 整数/无符号/浮点、null 共九组场景,且对 binary 用例特意断言清空后 !j.empty() 且类型仍为 binary。这些测试是 clear() 各类型行为的最直接可验证依据。

版本历史

  • 1.0.0 版本起提供 clear()
  • 3.8.0 版本起支持 binary 类型(此前的版本中 clear() 对 binary 没有分支)。

实践要点小结

  • 当你需要“复用”一个 json 变量(例如在循环中反复解析/构建同构 JSON)时,clear() 是比整体赋值更便宜的清空方式:它保留类型标签,标量场景下只是几个字节的赋值;
  • clear() 不会改变类型,也不会改变 binary 值的 subtype;如需回到 null 或切换类型,应显式构造新的 json
  • 调用 clear() 后必须使所有旧迭代器、get_ptr() 返回的指针、以及通过 get_ref 取到的引用失效,否则会触发未定义行为。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384