From 8f99919102fb35f6703ce14f706826c436bd5f55 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Tue, 13 Jun 2017 23:08:38 -0400 Subject: [PATCH] Update make_shared documentation --- doc/smart_ptr/make_shared.adoc | 256 +++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) diff --git a/doc/smart_ptr/make_shared.adoc b/doc/smart_ptr/make_shared.adoc index 53af79d..22522e8 100644 --- a/doc/smart_ptr/make_shared.adoc +++ b/doc/smart_ptr/make_shared.adoc @@ -1,5 +1,6 @@ //// Copyright 2017 Peter Dimov +Copyright 2017 Glen Joseph Fernandes (glenjofe@gmail.com) Distributed under the Boost Software License, Version 1.0. @@ -13,3 +14,258 @@ http://www.boost.org/LICENSE_1_0.txt :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 { + template + shared_ptr make_shared(Args&&... args); + template + shared_ptr allocate_shared(const A& a, Args&&... args); + + template + shared_ptr make_shared(std::size_t n); + template + shared_ptr allocate_shared(const A& a, std::size_t n); + + template + shared_ptr make_shared(); + template + shared_ptr allocate_shared(const A& a); + + template + shared_ptr make_shared(std::size_t n, _see below_ v); + template + shared_ptr allocate_shared(const A& a, std::size_t n, _see below_ v); + + template + shared_ptr make_shared(_see below_ v); + template + shared_ptr allocate_shared(const A& a, _see below_ v); + + template + shared_ptr make_shared_noinit(); + template + shared_ptr allocate_shared_noinit(const A& a); + + template + shared_ptr make_shared_noinit(std::size_t n); + template + shared_ptr allocate_shared_noinit(const A& a, std::size_t n); +} +``` + +## Free Functions + +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:: 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<__A2__>::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 rebound copy `a` such that its `value_type` is `_U_`. +* 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<__A2__>::construct(__a2__, __p__)`, where +`p` points to storage suitable to hold an object of type `_U_` and `_a2_` of +type `_A2_` is a rebound copy of `a` such that its value_type is `_U_`. +* 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. + +``` +template + shared_ptr make_shared(Args&&... args); +``` +:: +``` +template + shared_ptr allocate_shared(const A& a, Args&&... args); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is not an array type. +Returns::: A `shared_ptr` to an object of type `T`, constructed from +`args$$...$$`. + +``` +template + shared_ptr make_shared(std::size_t n); +``` +:: +``` +template + shared_ptr allocate_shared(const A& a, std::size_t n); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is an array type of the form `__U__[]`. +Returns::: A `shared_ptr` to a sequence of `n` value-initialized objects of +type `_U_`. + +``` +template + shared_ptr make_shared(); +``` +:: +``` +template + shared_ptr allocate_shared(const A& a); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is an array type of the form `__U__[__N__]`. +Returns::: A `shared_ptr` to a sequence of `_N_` value-initialized objects of +type `_U_`. + +[subs=+quotes] +``` +template + shared_ptr make_shared(std::size_t n, _see below_ v); +``` +:: +[subs=+quotes] +``` +template + shared_ptr allocate_shared(const A& a, std::size_t n, _see below_ v); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is an array type of the form `__U__[]`. +Returns::: A `shared_ptr` to a sequence of `n` objects of type `_U_`, each +initialized to `v`. + +[subs=+quotes] +``` +template + shared_ptr make_shared(_see below_ v); +``` +:: +[subs=+quotes] +``` +template + shared_ptr allocate_shared(const A& a, _see below_ v); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is an array type of the form `__U__[__N__]`. +Returns::: A `shared_ptr` to a sequence of `_N_` objects of type `_U_`, each +initialized to `v`. + +``` +template + shared_ptr make_shared_noinit(); +``` +:: +``` +template + shared_ptr allocate_shared_noinit(const A& a); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is not an array type, or an array type of the `__U__[__N__]`. +Returns::: A `shared_ptr` to a default-initialized object of type `T`, or a +sequence of `_N_` default-initialized objects of type `_U_`, respectively. + +``` +template + shared_ptr make_shared_noinit(std::size_t n); +``` +:: +``` +template + shared_ptr allocate_shared_noinit(const A& a, std::size_t n); +``` +:: +Remarks::: These overloads shall only participate in overload resolution when +`T` is an array type of the form `__U__[]`. +Returns::: A `shared_ptr` to a sequence of `_n_` default-initialized objects +of type `_U_`.