|  | Home | Libraries | People | FAQ | More | 
        Variable-length containers in this library all use dynamically allocated
        memory to store their contents. Callers can gain control over the strategy
        used for allocation by specifying a storage_ptr in select constructors
        and function parameter lists. A storage_ptr has these properties:
      
memory_resource.
          memory_resource*
            or polymorphic_allocator do not
            acquire ownership; the caller is responsible for ensuring that the lifetime
            of the resource extends until it is no longer referenced.
          make_shared_resource acquires
            shared ownership of the memory resource; the lifetime of the resource
            is extended until all copies of the storage pointer are destroyed.
          is_deallocate_trivial before
            type-erasing the resource, allowing the value to be queried at run-time.
          This lists all of the allocation-related types and functions available when using the library:
Table 1.7. Functions and Types
| Name | Description | 
|---|---|
| Returns a pointer to a memory resource instance which always throws an exception upon allocation. This is used to to achieve the invariant that no parsing or container operation will dynamically allocate memory. | |
| A customization point allowing a memory resource type to indicate that calls to deallocate are trivial. | |
| A function returning a smart pointer with shared ownership of a newly allocated memory resource. | |
| The abstract base class representing an allocator. | |
| A memory resource which allocates large blocks of memory and has a trivial deallocate function. Allocated memory is not freed until the resource is destroyed, making it fast for parsing but not suited for performing modifications. | |
| 
                  An Allocator
                  which uses a reference to a  | |
| A memory resource that uses a single caller provided buffer. No dynamic allocations are used. This is fast for parsing but not suited for performing modifications. | |
| 
                  A smart pointer through which a  | 
        The default memory resource wraps calls to the global
        heap allocation functions. This resource is not reference counted and has
        a non-trivial deallocate function. All default-constructed storage_ptr reference the same default
        memory resource:
      
storage_ptr sp1; storage_ptr sp2; assert( sp1.get() != nullptr ); // always points to a valid resource assert( sp1.get() == sp2.get() ); // both point to the default resource assert( *sp1.get() == *sp2.get() ); // the default resource compares equal
Default-constructed library containers use the default memory resource:
array arr; // default construction object obj; string str; value jv; assert( jv.storage().get() == storage_ptr().get() ); // uses the default memory resource assert( jv.storage().get() == arr.storage().get() ); // both point to the default resource assert( *arr.storage() == *obj.storage() ); // containers use equivalent resources
The default memory resource is well suited for general usage. It offers reasonable performance for parsing, and conservative memory usage for modification of the contents of containers.
Consider the pattern of memory allocation during parsing: when an array, object, or string is encountered the parser accumulates elements in its temporary storage area. When all of the elements are known, a single memory allocation is requested from the resource when constructing the value. Thus, parsing only allocates and constructs containers at their final size. Memory is not reallocated; that is, a memory buffer never needs to grow by allocating a new larger buffer and deallocating the previous buffer.
        The monotonic_resource optimizes this
        memory allocation pattern by allocating increasingly large blocks of global
        memory internally and parceling those blocks out in smaller pieces to fulfill
        allocation requests. It has a trivial deallocate function. The monotonic
        resource does not actually deallocate memory until the resource is destroyed.
        Thus, it is ideally suited for the use-case where JSON is parsed, and the
        resulting value is then inspected but not modified.
      
        The resource to use when constructing values may be specified in calls to
        parse
        as shown here:
      
monotonic_resource mr; value const jv = parse( "[1,2,3]", &mr );
Or, to parse into a value with shared ownership of the memory resource:
value parse_value( string_view s) { return parse( s, make_shared_resource< monotonic_resource >() ); }
A monotonic resource may be optionally constructed with an initial buffer to use first, before going to the heap. This allows the caller to use stack space and avoid dynamic allocations for most parsed JSON, falling back to dynamic allocation from the heap if the input JSON is larger than average, as shown here:
template< class Handler > void do_rpc( string_view s, Handler&& h ) { unsigned char buffer[ 8192 ]; // Small stack buffer to avoid most allocations during parse monotonic_resource mr( buffer ); // This resource will use our local buffer first value const jv = parse( s, &mr ); // Parse the input string into a value that uses our resource h( jv ); // Call the handler to perform the RPC command }
        A static_resource
        constructs from a caller-provided buffer, and satisfies all memory allocation
        requests from the buffer. Once the buffer is exhausted, subsequent calls
        to allocate throw the exception std::bad_alloc.
        The resource offers a simple invariant: dynamic heap allocations are never
        performed.
      
To use the resource, construct it with a local buffer:
unsigned char buffer[ 8192 ]; static_resource mr( buffer ); // The resource will use our local buffer
        The function get_null_resource returns a global
        instance of the null resource. This resource offers a simple invariant: all
        calls to allocate will throw the exception std::bad_alloc.
        An instance of the null resource can be used to make parsing guarantee that
        allocations from the heap are never made. This is explored in more detail
        in a later section.
      
        The containers array, object, and value all propagate the memory resource
        they were constructed with to child elements:
      
monotonic_resource mr; array arr( &mr ); // construct an array using our resource arr.emplace_back( "boost" ); // insert a string assert( *arr[0].as_string().storage() == mr ); // the resource is propagated to the string
This propagation acts recursively, containers within containers will all have the resource propagated. Once a container is constructed, its memory resource can never be changed.
        It is important to note that storage_ptr supports both shared-ownership
        and reference lifetime models. Construction from a memory resource pointer
        does not transfer ownership:
      
{ monotonic_resource mr; array arr( &mr ); // construct an array using our resource assert( ! arr.storage().is_shared() ); // no shared ownership }
        When using a memory resource in this fashion, including the case where a
        storage pointer or container is constructed from a polymorphic_allocator, the caller
        must ensure that the lifetime of the resource is extended until it is no
        longer referenced by any variables; otherwise, undefined behavior is possible.
      
        Shared ownership is achieved using the function make_shared_resource, which creates
        a new, reference-counted memory resource using a dynamic memory allocation
        and returns it as a storage_ptr:
      
storage_ptr sp = make_shared_resource< monotonic_resource >(); string str( sp ); assert( sp.is_shared() ); // shared ownership assert( str.storage().is_shared() ); // shared ownership
When a storage pointer is constructed this way, the lifetime of the referenced memory resource is extended until all variables which reference it are destroyed.
        To implement custom memory allocation strategies, derive your class from
        memory_resource
        and implement the functions do_allocate,
        do_deallocate, and do_is_equal as seen in this example below,
        which logs each operation it performs to the console:
      
class logging_resource : public memory_resource { private: void* do_allocate( std::size_t bytes, std::size_t align ) override { std::cout << "Allocating " << bytes << " bytes with alignment " << align << '\n'; return ::operator new( bytes ); } void do_deallocate( void* ptr, std::size_t bytes, std::size_t align ) override { std::cout << "Deallocating " << bytes << " bytes with alignment " << align << " @ address " << ptr << '\n'; return ::operator delete( ptr ); } bool do_is_equal( memory_resource const& other ) const noexcept override { // since the global allocation and deallocation functions are used, // any instance of a logging_resource can deallocate memory allocated // by another instance of a logging_resource return dynamic_cast< logging_resource const* >( &other ) != nullptr; } };