//// Copyright 2017 Peter Dimov Copyright 2017 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt //// [#make_shared] # make_shared: Creating shared_ptr :toc: :toc-title: :idprefix: make_shared_ ## Description The function templates `make_shared` and `allocate_shared` provide convenient, safe and efficient ways to create `shared_ptr` objects. ## Rationale Consistent use of `shared_ptr` can eliminate the need to use an explicit `delete`, but alone it provides no support in avoiding explicit `new`. There were repeated requests from users for a factory function that creates an object of a given type and returns a `shared_ptr` to it. Besides convenience and style, such a function is also exception safe and considerably faster because it can use a single allocation for both the object and its corresponding control block, eliminating a significant portion of `shared_ptr` construction overhead. This eliminates one of the major efficiency complaints about `shared_ptr`. The family of overloaded function templates, `make_shared` and `allocate_shared`, were provided to address this need. `make_shared` uses the global `operator new` to allocate memory, whereas `allocate_shared` uses an user-supplied allocator, allowing finer control. The rationale for choosing the name `make_shared` is that the expression `make_shared()` can be read aloud and conveys the intended meaning. Originally the Boost function templates `allocate_shared` and `make_shared` were provided for scalar objects only. There was a need to have efficient allocation of array objects. One criticism of class template `shared_array` was always the lack of a utility like `make_shared` that uses only a single allocation. When `shared_ptr` was enhanced to support array types, additional overloads of `allocate_shared` and `make_shared` were provided for array types. ## Synopsis `make_shared` and `allocate_shared` are defined in ``. [subs=+quotes] ``` namespace boost { `// T is not an array` template shared_ptr make_shared(Args&&... args); template shared_ptr allocate_shared(const A& a, Args&&... args); `// T is an array of unknown bounds` template shared_ptr make_shared(std::size_t n); template shared_ptr allocate_shared(const A& a, std::size_t n); `// T is an array of known bounds` template shared_ptr make_shared(); template shared_ptr allocate_shared(const A& a); `// T is an array of unknown bounds` template shared_ptr make_shared(std::size_t n, const remove_extent_t& v); template shared_ptr allocate_shared(const A& a, std::size_t n, const remove_extent_t& v); `// T is an array of known bounds` template shared_ptr make_shared(const remove_extent_t& v); template shared_ptr allocate_shared(const A& a, const remove_extent_t& v); `// T is not an array of unknown bounds` template shared_ptr make_shared_noinit(); template shared_ptr allocate_shared_noinit(const A& a); `// T is an array of unknown bounds` template shared_ptr make_shared_noinit(std::size_t n); template shared_ptr allocate_shared_noinit(const A& a, std::size_t n); } ``` ## Common Requirements The common requirements that apply to all `make_shared` and `allocate_shared` overloads, unless specified otherwise, are described below. Requires:: `A` shall be an _allocator_. The copy constructor and destructor of `A` shall not throw exceptions. Effects:: Allocates memory for an object of type `T` or `n` objects of `U` (if `T` is an array type of the form `U[]` and `n` is determined by arguments, as specified by the concrete overload). The object is initialized from arguments as specified by the concrete overload. Uses a rebound copy of `a` (for an unspecified `value_type`) to allocate memory. If an exception is thrown, the functions have no effect. Returns:: A `shared_ptr` instance that stores and owns the address of the newly constructed object. Postconditions:: `r.get() != 0` and `r.use_count() == 1`, where `r` is the return value. Throws:: `std::bad_alloc`, an exception thrown from `A::allocate`, or from the initialization of the object. Remarks:: * Performs no more than one memory allocation. This provides efficiency equivalent to an intrusive smart pointer. * When an object of an array type is specified to be initialized to a value of the same type `v`, this shall be interpreted to mean that each array element of the object is initialized to the corresponding element from `v`. * When an object of an array type is specified to be value-initialized, this shall be interpreted to mean that each array element of the object is value-initialized. * When a (sub)object of non-array type `U` is specified to be initialized to a value `v`, or constructed from `args\...`, `make_shared` shall perform this initialization via the expression `::new(p) U(expr)` (where `_expr_` is `v` or `std::forward(args)\...)` respectively) and `p` has type `void*` and points to storage suitable to hold an object of type `U`. * When a (sub)object of non-array type `U` is specified to be initialized to a value `v`, or constructed from `args\...`, `allocate_shared` shall perform this initialization via the expression `std::allocator_traits::construct(a2, p, expr)` (where `_expr_` is `v` or `std::forward(args)\...)` respectively), `p` points to storage suitable to hold an object of type `U`, and `a2` of type `A2` is a potentially rebound copy of `a`. * When a (sub)object of non-array type `U` is specified to be default-initialized, `make_shared_noinit` and `allocate_shared_noinit` shall perform this initialization via the expression `::new(p) U`, where `p` has type `void*` and points to storage suitable to hold an object of type `U`. * When a (sub)object of non-array type `U` is specified to be value-initialized, `make_shared` shall perform this initialization via the expression `::new(p) U()`, where `p` has type `void*` and points to storage suitable to hold an object of type `U`. * When a (sub)object of non-array type `U` is specified to be value-initialized, `allocate_shared` shall perform this initialization via the expression `std::allocator_traits::construct(a2, p)`, where `p` points to storage suitable to hold an object of type `U` and `a2` of type `A2` is a potentially rebound copy of `a`. * Array elements are initialized in ascending order of their addresses. * When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements should be destroyed in the reverse order of their construction. NOTE: These functions will typically allocate more memory than the total size of the element objects to allow for internal bookkeeping structures such as the reference counts. ## Free Functions ``` template shared_ptr make_shared(Args&&... args); ``` ``` template shared_ptr allocate_shared(const A& a, Args&&... args); ``` [none] * {blank} + Constraints:: `T` is not an array. Returns:: A `shared_ptr` to an object of type `T`, constructed from `args\...`. Examples:: * `auto p = make_shared();` * `auto p = make_shared >(16, 1);` ``` template shared_ptr make_shared(std::size_t n); ``` ``` template shared_ptr allocate_shared(const A& a, std::size_t n); ``` [none] * {blank} + Constraints:: `T` is an array of unknown bounds. Returns:: A `shared_ptr` to a sequence of `n` value-initialized objects of type `remove_extent_t`. Examples:: * `auto p = make_shared(1024);` * `auto p = make_shared(6);` ``` template shared_ptr make_shared(); ``` ``` template shared_ptr allocate_shared(const A& a); ``` [none] * {blank} + Constraints:: `T` is an array of known bounds. Returns:: A `shared_ptr` to a sequence of `extent_v` value-initialized objects of type `remove_extent_t`. Examples:: * `auto p = make_shared();` * `auto p = make_shared();` ``` template shared_ptr make_shared(std::size_t n, const remove_extent_t& v); ``` ``` template shared_ptr allocate_shared(const A& a, std::size_t n, const remove_extent_t& v); ``` [none] * {blank} + Constraints:: `T` is an array of unknown bounds. Returns:: A `shared_ptr` to a sequence of `n` objects of type `remove_extent_t`, each initialized to `v`. Examples:: * `auto p = make_shared(1024, 1.0);` * `auto p = make_shared(6, {1.0, 0.0});` * `auto p = make_shared[]>(4, {1, 2});` ``` template shared_ptr make_shared(const remove_extent_t& v); ``` ``` template shared_ptr allocate_shared(const A& a, const remove_extent_t& v); ``` [none] * {blank} + Constraints:: `T` is an array of known bounds. Returns:: A `shared_ptr` to a sequence of `extent_v` objects of type `remove_extent_t`, each initialized to `v`. Examples:: * `auto p = make_shared(1.0);` * `auto p = make_shared({1.0, 0.0});` * `auto p = make_shared[4]>({1, 2});` ``` template shared_ptr make_shared_noinit(); ``` ``` template shared_ptr allocate_shared_noinit(const A& a); ``` [none] * {blank} + Constraints:: `T` is not an array, or is an array of known bounds. Returns:: A `shared_ptr` to a default-initialized object of type `T`, or a sequence of `extent_v` default-initialized objects of type `remove_extent_t`, respectively. Example:: `auto p = make_shared_noinit();` ``` template shared_ptr make_shared_noinit(std::size_t n); ``` ``` template shared_ptr allocate_shared_noinit(const A& a, std::size_t n); ``` [none] * {blank} + Constraints:: `T` is an array of unknown bounds. Returns:: A `shared_ptr` to a sequence of `_n_` default-initialized objects of type `remove_extent_t`. Example:: `auto p = make_shared_noinit(1024);`