blob: 7e3026ca94ef51ef99b32c92e528595b4d608ecd [file] [log] [blame]
////
Copyright 2019 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
////
[#allocate_unique]
# allocate_unique: Creating unique_ptr
:toc:
:toc-title:
:idprefix: allocate_unique_
## Description
The `allocate_unique` family of function templates provide convenient and safe
ways to obtain a `std::unique_ptr` that manages a new object created using an
allocator.
## Rationale
The {cpp}14 standard introduced `std::make_unique` which used operator `new` to
create new objects. However, there is no convenient facility in the standard
library to use an allocator for the creation of the objects managed by
`std::unique_ptr`. Users writing allocator aware code have often requested an
`allocate_unique` factory function. This function is to `std::unique_ptr` what
`std::allocate_shared` is to `std::shared_ptr`.
## Synopsis
`allocate_unique` is defined in `<boost/smart_ptr/allocate_unique.hpp>`.
[subs=+quotes]
```
namespace boost {
template<class T, class A>
class alloc_deleter;
template<class T, class A>
using alloc_noinit_deleter = alloc_deleter<T, noinit_adaptor<A>>;
`// T is not an array`
template<class T, class A, class... Args>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, Args&&... args);
`// T is not an array`
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, type_identity_t<T>&& v);
`// T is an array of unknown bounds`
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, std::size_t n);
`// T is an array of known bounds`
template<class T, class A>
std::unique_ptr<remove_extent_t<T>[], alloc_deleter<T, A>>
allocate_unique(const A& a);
`// T is an array of unknown bounds`
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, std::size_t n, const remove_extent_t<T>& v);
`// T is an array of known bounds`
template<class T, class A>
std::unique_ptr<remove_extent_t<T>[], alloc_deleter<T, A>>
allocate_unique(const A& a, const remove_extent_t<T>& v);
`// T is not an array`
template<class T, class A>
std::unique_ptr<T, alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a);
`// T is an array of unknown bounds`
template<class T, class A>
std::unique_ptr<T, alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a, std::size_t n);
`// T is an array of known bounds`
template<class T, class A>
std::unique_ptr<remove_extent_t<T>[], alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a);
}
```
## Common Requirements
The common requirements that apply to all `allocate_unique` and
`allocate_unique_noinit` 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 `std::unique_ptr` instance that stores and owns the address of the
newly constructed object.
Postconditions:: `r.get() != 0`, where `r` is the return value.
Throws:: An exception thrown from `A::allocate`, or from the initialization of
the object.
Remarks::
* 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\...`, `allocate_unique` 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 potentially rebound
copy of `a`.
* When a (sub)object of non-array type `U` is specified to be
default-initialized, `allocate_unique_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, `allocate_unique` 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
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.
## Free Functions
```
template<class T, class A, class... Args>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, Args&&... args);
```
[none]
* {blank}
+
Constraints:: `T` is not an array.
Returns:: A `std::unique_ptr` to an object of type `T`, constructed from
`args\...`.
Examples::
* `auto p = allocate_unique<int>(a);`
* `auto p = allocate_unique<std::vector<int>>(a, 16, 1);`
```
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, type_identity_t<T>&& v);
```
[none]
* {blank}
+
Constraints:: `T` is not an array.
Returns:: A `std::unique_ptr` to an object of type `T`, constructed from `v`.
Example:: `auto p = allocate_unique<std::vector<int>>(a, {1, 2});`
```
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, std::size_t n);
```
[none]
* {blank}
+
Constraints:: `T` is an array of unknown bounds.
Returns:: A `std::unique_ptr` to a sequence of `n` value-initialized objects of
type `remove_extent_t<T>`.
Examples::
* `auto p = allocate_unique<double[]>(a, 1024);`
* `auto p = allocate_unique<double[][2][2]>(a, 6);`
```
template<class T, class A>
std::unique_ptr<remove_extent_t<T>[], alloc_deleter<T, A>>
allocate_unique(const A& a);
```
[none]
* {blank}
+
Constraints:: `T` is an array of known bounds.
Returns:: A `std::unique_ptr` to a sequence of `extent_v<T>` value-initialized
objects of type `remove_extent_t<T>`.
Examples::
* `auto p = allocate_unique<double[1024]>(a);`
* `auto p = allocate_unique<double[6][2][2]>(a);`
```
template<class T, class A>
std::unique_ptr<T, alloc_deleter<T, A>>
allocate_unique(const A& a, std::size_t n, const remove_extent_t<T>& v);
```
[none]
* {blank}
+
Constraints:: `T` is an array of unknown bounds.
Returns:: A `std::unique_ptr` to a sequence of `n` objects of type
`remove_extent_t<T>`, each initialized to `v`.
Examples::
* `auto p = allocate_unique<double[]>(a, 1024, 1.0);`
* `auto p = allocate_unique<double[][2]>(a, 6, {1.0, 0.0});`
* `auto p = allocate_unique<std::vector<int>[]>(a, 4, {1, 2});`
```
template<class T, class A>
std::unique_ptr<remove_extent_t<T>[], alloc_deleter<T, A>>
allocate_unique(const A& a, const remove_extent_t<T>& v);
```
[none]
* {blank}
+
Constraints:: `T` is an array of known bounds.
Returns:: A `std::unique_ptr` to a sequence of `extent_v<T>` objects of type
`remove_extent_t<T>`, each initialized to `v`.
Examples::
* `auto p = allocate_unique<double[1024]>(a, 1.0);`
* `auto p = allocate_unique<double[6][2]>(a, {1.0, 0.0});`
* `auto p = allocate_unique<std::vector<int>[4]>(a, {1, 2});`
```
template<class T, class A>
std::unique_ptr<T, alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a);
```
[none]
* {blank}
+
Constraints:: `T` is not an array.
Returns:: A `std::unique_ptr` to a default-initialized object of type `T`.
Example:: `auto p = allocate_unique_noinit<double>(a);`
```
template<class T, class A>
std::unique_ptr<T, alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a, std::size_t n);
```
[none]
* {blank}
+
Constraints:: `T` is an array of unknown bounds.
Returns:: A `std::unique_ptr` to a sequence of `n` default-initialized objects
of type `remove_extent_t<T>`.
Example:: `auto p = allocate_unique_noinit<double[]>(a, 1024);`
```
template<class T, class A>
std::unique_ptr<remove_extent_t<T>, alloc_noinit_deleter<T, A>>
allocate_unique_noinit(const A& a);
```
[none]
* {blank}
+
Constraints:: `T` is an array of known bounds.
Returns:: A `std::unique_ptr` to a sequence of `extent_v<T>`
default-initialized objects of type `remove_extent_t<T>`.
Example:: `auto p = allocate_unique_noinit<double[1024]>(a);`
## Deleter
Class template `alloc_deleter` is the deleter used by the `allocate_unique`
functions.
### Synopsis
[subs=+quotes]
```
template<class T, class A>
class alloc_deleter {
public:
using pointer = `unspecified`;
explicit alloc_deleter(const A& a) noexcept;
void operator()(pointer p);
};
```
### Members
[subs=+quotes]
```
using pointer = `unspecified`;
```
[none]
* {blank}
+
A type that satisfies _NullablePointer_.
```
explicit alloc_deleter(const A& a) noexcept;
```
[none]
* {blank}
+
Effects:: Initializes the stored allocator from `a`.
```
void operator()(pointer p);
```
[none]
* {blank}
+
Effects:: Destroys the objects and deallocates the storage referenced by `p`,
using the stored allocator.