deploy: 94fe31eb9b
This commit is contained in:
1 parent
41c601a7d1
commit
d2e264bd84
1400 files changed
+11859
-5440
No files matched your search
@@ -51,13 +51,22 @@ If insertion order matters *and* an object routinely has many thousands of keys,
|
||||
|
||||
## Avoiding copies
|
||||
|
||||
- **Move instead of copy.** Constructing a `basic_json` from an existing one is [linear in its size](https://json.nlohmann.me/api/basic_json/basic_json/#complexity) for the copy constructor but [constant](https://json.nlohmann.me/api/basic_json/basic_json/#complexity) for the move constructor. The same applies to assigning a large `std::string`, `std::vector`, or other container into a value: pass it as `std::move(x)` rather than `x` whenever `x` is no longer needed afterwards.
|
||||
- **Move instead of copy.** Constructing a `basic_json` from an existing one is [linear in its size](https://json.nlohmann.me/api/basic_json/basic_json/#complexity) for the copy constructor but [constant](https://json.nlohmann.me/api/basic_json/basic_json/#complexity) for the move constructor. The same applies to assigning a large `std::string`, `std::vector`, or other container into a value: pass it as `std::move(x)` rather than `x` whenever `x` is no longer needed afterwards. Since version 3.13.0 unreleased, converting an rvalue container (`json j = std::move(vec);`) moves the elements instead of copying them; the source is then left in a valid but unspecified state.
|
||||
- **Access without copying.** [`get<T>()`](https://json.nlohmann.me/api/basic_json/get/index.md) returns a copy of the stored value converted to `T`. When a reference or pointer to the value already stored inside the `basic_json` is enough, [`get_ref()`](https://json.nlohmann.me/api/basic_json/get_ref/index.md) and [`get_ptr()`](https://json.nlohmann.me/api/basic_json/get_ptr/index.md) access it directly: both pages state, word for word, "No copies are made." -- at the cost of that reference or pointer becoming invalid once the underlying value changes.
|
||||
- **Iterate by reference.** `basic_json::iterator::operator*()` returns a `reference` (an alias for `basic_json&`), but a range-based for loop with a by-value loop variable (`for (auto el : j)`) still copies each element, because plain `auto` drops the reference. Write `for (const auto& el : j)` (or `auto&` for a mutable loop), and use [`items()`](https://json.nlohmann.me/api/basic_json/items/index.md) the same way when the key is needed too -- its own examples use `for (auto& el : j.items())`.
|
||||
- **Construct in place.** [`emplace_back()`](https://json.nlohmann.me/api/basic_json/emplace_back/index.md) (arrays, amortized constant time) and [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/index.md) (objects, logarithmic in the size of the container for `json`) forward their arguments directly to a `basic_json` constructor, rather than requiring a temporary value to be constructed and then copied or moved in. [`push_back()`](https://json.nlohmann.me/api/basic_json/push_back/index.md) has an rvalue overload (`push_back(basic_json&&)`) for a value that already exists: `j.push_back(std::move(value))` moves it in instead of copying it.
|
||||
- **Skip the bounds check when it is redundant.** [`at()`](https://json.nlohmann.me/api/basic_json/at/index.md) and [`operator[]`](https://json.nlohmann.me/api/basic_json/operator%5B%5D/index.md) have the same complexity (constant for a valid array index, logarithmic for an object key in `json`) -- the difference is that `at()` additionally checks the key or index and throws if it is invalid, while `operator[]` does not (see [unchecked access](https://json.nlohmann.me/features/element_access/unchecked_access/index.md) and [checked access](https://json.nlohmann.me/features/element_access/checked_access/index.md)). Prefer `operator[]` when the surrounding code has already established that the access is valid.
|
||||
- **Reserve array capacity.** `basic_json` has no public `reserve()`, but when building a large array incrementally with a known final size, [`get_ref()`](https://json.nlohmann.me/api/basic_json/get_ref/index.md) exposes the underlying `array_t` so it can be reserved directly -- see ["reserving array capacity"](https://json.nlohmann.me/features/element_access/unchecked_access/#performance-reserving-array-capacity) for the one-line recipe.
|
||||
|
||||
## Memory
|
||||
|
||||
- **A value is small, its content is on the heap.** A `basic_json` is 16 bytes on a 64-bit platform (a type tag and a union). Strings, arrays, objects, and binary values are allocated on the heap and owned by the value. Destroying the value frees everything it owns.
|
||||
- **Copies are deep.** After `json b = a;`, changing `b` does not change `a`, and both own their memory. Copying a large value therefore doubles its memory; see [Avoiding copies](#avoiding-copies). `auto x = j["key"];` is a copy, `auto& x = j["key"];` is not.
|
||||
- **A moved-from value is `null`.** After `json c = std::move(a);` the value `a` is `null` and owns nothing.
|
||||
- **Reading does not require a tree.** If you only read the data, parse it into a [`json_document`](https://json.nlohmann.me/features/json_view/index.md) (`<nlohmann/json_view.hpp>`, added in version 3.13.0 unreleased) instead of a `basic_json`. It stores 16 bytes per value, does not copy floating-point numbers or strings without escape sequences out of the text, and creates no `basic_json` value except for the parts you [`materialize()`](https://json.nlohmann.me/api/basic_json_view/materialize/index.md). A document that borrows the text needs the text to outlive it; see [Zero-copy JSON views](https://json.nlohmann.me/features/json_view/index.md).
|
||||
- **Containers keep their capacity.** `clear()` and `erase()` on an array remove the elements, but the underlying `std::vector` keeps its allocated capacity, like `std::vector::clear` does. To give the memory back, assign a new value (`j = json::array();`) or destroy the value.
|
||||
- **Freed memory does not always go back to the operating system.** The library returns memory to the allocator (`std::allocator` by default, or the [one you configured](https://json.nlohmann.me/features/types/template_parameters/index.md)). Whether the process size shrinks then depends on the allocator and the platform, as for any C++ program. A process that parses a large document and drops it is not leaking if its resident size stays high; run it under a tool such as [Valgrind](https://valgrind.org) or the sanitizers to tell a leak from retained memory.
|
||||
|
||||
## Serialization
|
||||
|
||||
[`dump()`](https://json.nlohmann.me/api/basic_json/dump/index.md) with the default `indent = -1` selects "the most compact representation" (word for word from the page); any non-negative `indent` pretty-prints instead, which is more readable but produces more bytes and more work. `dump()` builds and returns a complete `string_t` containing the whole serialization. [`operator<<`](https://json.nlohmann.me/api/operator_ltlt/index.md) writes directly to a `std::ostream` instead, through the same serializer, but without ever materializing that intermediate string -- so if the destination is a stream (a file, or `std::cout`), `os << j;` avoids the allocation and copy that `os << j.dump();` would incur for large values.
|
||||
|
||||
Reference in new issue
Block a user