Update make_shared documentation

This commit is contained in:
Glen Fernandes
2017-06-13 23:08:38 -04:00
parent 420626d6d9
commit 8f99919102

View File

@@ -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<Widget>()` 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
`<boost/smart_ptr/make_shared.hpp>`.
[subs=+quotes]
```
namespace boost {
template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);
template<class T, class A, class... Args>
shared_ptr<T> allocate_shared(const A& a, Args&&... args);
template<class T>
shared_ptr<T> make_shared(std::size_t n);
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, std::size_t n);
template<class T>
shared_ptr<T> make_shared();
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a);
template<class T>
shared_ptr<T> make_shared(std::size_t n, _see below_ v);
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, std::size_t n, _see below_ v);
template<class T>
shared_ptr<T> make_shared(_see below_ v);
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, _see below_ v);
template<class T>
shared_ptr<T> make_shared_noinit();
template<class T, class A>
shared_ptr<T> allocate_shared_noinit(const A& a);
template<class T>
shared_ptr<T> make_shared_noinit(std::size_t n);
template<class T, class A>
shared_ptr<T> 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>(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>(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<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);
```
::
```
template<class T, class A, class... Args>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared(std::size_t n);
```
::
```
template<class T, class A>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared();
```
::
```
template<class T, class A>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared(std::size_t n, _see below_ v);
```
::
[subs=+quotes]
```
template<class T, class A>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared(_see below_ v);
```
::
[subs=+quotes]
```
template<class T, class A>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared_noinit();
```
::
```
template<class T, class A>
shared_ptr<T> 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<class T>
shared_ptr<T> make_shared_noinit(std::size_t n);
```
::
```
template<class T, class A>
shared_ptr<T> 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_`.