Files
json/docs/mkdocs/docs/features/json_view/lifetime.md
T
Niels Lohmann f64464daf1 Split the json_view feature page into sub-pages
The single features/json_view.md page grew to ~600 lines covering eight
topics. Split it into features/json_view/ with an overview page and
pages for ownership and lifetime, differences from basic_json, reading
values, generic code, editing, and images.

The new differences page collects what was spread over several sections
("What is the same", "What is different", "Duplicate keys", and notes in
the conversion and serialization sections) under one summary table, and
adds the parts of the basic_json interface a view does not have. The
other pages now link to it instead of restating the rules.

Internal links across the documentation point to the new pages.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-11-02 20:42:55 +01:00

4.0 KiB

Ownership and lifetime

A document either borrows the text it was parsed from, or owns its own copy of it; call owns_source() to find out which happened. parse() decides this from the value category and type of its argument (an lvalue #!cpp std::string is borrowed; an rvalue #!cpp std::string is moved in, owned without a copy; a stream is read into an owned buffer; and so on — see parse's Notes for the full table). parse_copy() always owns a copy, regardless of the input.

!!! warning "A borrowed document depends on your buffer"

If a document borrows its text, that text **must outlive the document** (and every view taken from it) and must
stay **unmodified** for as long as the document exists, since floating-point values and unescaped strings are
read from it lazily. Reading or writing through a view after the underlying buffer is gone is undefined behavior,
exactly as it would be for a dangling `#!cpp std::string_view`.

When a view is valid

A view is valid only while all of the following hold:

  • the document is alive,
  • the document has not been re-parsed since the view was taken (with read() or parse() into it),
  • the document has not had shrink_to_fit() called on it since, and
  • if the document borrows its source text, that text is still alive and unmodified.

Moving the basic_json_document<> itself is fine and does not invalidate its views: the index is a separate heap allocation that keeps its address across the move. Take a fresh view from root() whenever any of the other conditions above was not met. Edits of an editable document keep views valid, too; see What stays valid.

--8<-- "images/json_view_lifetime.svg"

Four timelines of a document and its views, each bar showing when an object is alive or valid and when it dangles. Destroying the borrowed text, re-parsing, or shrinking the document invalidates the views taken before; moving the document does not.

Why views can dangle

A view can dangle, exactly like a #!cpp std::string_view: nothing stops you from using it after its document is gone. This is deliberate. A view is two pointers and trivially copyable; making it safe (a #!cpp std::shared_ptr in the document and a #!cpp std::weak_ptr in each view) would make it larger, add reference counting to every copy, and a lock() to every access — exactly the costs the view exists to avoid. What is caught is the obvious case: because a view dies with its document, root() is not callable on a temporary document: #!cpp auto v = json_document::parse(text).root(); does not compile. Give the document a name first.

The same holds for what a view hands out without copying: a string from get_string(), a token from number_token(), and string_view members of decoded structs are valid only as long as the document and, if it borrows, its source text.

??? example "Example: borrowed and owned documents, and when views become invalid"

```cpp
--8<-- "examples/json_view_ownership.cpp"
```

Output:

```json
--8<-- "examples/json_view_ownership.output"
```

See also

Version history

  • Added in version 3.13.0.