• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1////
2Copyright 2017 Peter Dimov
3Copyright 2017 Glen Joseph Fernandes (glenjofe@gmail.com)
4
5Distributed under the Boost Software License, Version 1.0.
6
7See accompanying file LICENSE_1_0.txt or copy at
8http://www.boost.org/LICENSE_1_0.txt
9////
10
11[#make_shared]
12# make_shared: Creating shared_ptr
13:toc:
14:toc-title:
15:idprefix: make_shared_
16
17## Description
18
19The function templates `make_shared` and `allocate_shared` provide convenient,
20safe and efficient ways to create `shared_ptr` objects.
21
22## Rationale
23
24Consistent use of `shared_ptr` can eliminate the need to use an explicit
25`delete`, but alone it provides no support in avoiding explicit `new`. There
26were repeated requests from users for a factory function that creates an
27object of a given type and returns a `shared_ptr` to it. Besides convenience
28and style, such a function is also exception safe and considerably faster
29because it can use a single allocation for both the object and its
30corresponding control block, eliminating a significant portion of
31`shared_ptr` construction overhead. This eliminates one of the major
32efficiency complaints about `shared_ptr`.
33
34The family of overloaded function templates, `make_shared` and
35`allocate_shared`, were provided to address this need. `make_shared` uses the
36global `operator new` to allocate memory, whereas `allocate_shared` uses an
37user-supplied allocator, allowing finer control.
38
39The rationale for choosing the name `make_shared` is that the expression
40`make_shared<Widget>()` can be read aloud and conveys the intended meaning.
41
42Originally the Boost function templates `allocate_shared` and `make_shared`
43were provided for scalar objects only. There was a need to have efficient
44allocation of array objects. One criticism of class template `shared_array`
45was always the lack of a utility like `make_shared` that uses only a single
46allocation. When `shared_ptr` was enhanced to support array types, additional
47overloads of `allocate_shared` and `make_shared` were provided for array
48types.
49
50## Synopsis
51
52`make_shared` and `allocate_shared` are defined in
53`<boost/smart_ptr/make_shared.hpp>`.
54
55[subs=+quotes]
56```
57namespace boost {
58  `// T is not an array`
59  template<class T, class... Args>
60    shared_ptr<T> make_shared(Args&&... args);
61  template<class T, class A, class... Args>
62    shared_ptr<T> allocate_shared(const A& a, Args&&... args);
63
64  `// T is an array of unknown bounds`
65  template<class T>
66    shared_ptr<T> make_shared(std::size_t n);
67  template<class T, class A>
68    shared_ptr<T> allocate_shared(const A& a, std::size_t n);
69
70  `// T is an array of known bounds`
71  template<class T>
72    shared_ptr<T> make_shared();
73  template<class T, class A>
74    shared_ptr<T> allocate_shared(const A& a);
75
76  `// T is an array of unknown bounds`
77  template<class T> shared_ptr<T>
78    make_shared(std::size_t n, const remove_extent_t<T>& v);
79  template<class T, class A> shared_ptr<T>
80    allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);
81
82  `// T is an array of known bounds`
83  template<class T>
84    shared_ptr<T> make_shared(const remove_extent_t<T>& v);
85  template<class T, class A>
86    shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v);
87
88  `// T is not an array of unknown bounds`
89  template<class T>
90    shared_ptr<T> make_shared_noinit();
91  template<class T, class A>
92    shared_ptr<T> allocate_shared_noinit(const A& a);
93
94  `// T is an array of unknown bounds`
95  template<class T>
96    shared_ptr<T> make_shared_noinit(std::size_t n);
97  template<class T, class A>
98    shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n);
99}
100```
101
102## Common Requirements
103
104The common requirements that apply to all `make_shared` and `allocate_shared`
105overloads, unless specified otherwise, are described below.
106
107Requires:: `A` shall be an _allocator_. The copy constructor and destructor
108of `A` shall not throw exceptions.
109
110Effects:: Allocates memory for an object of type `T`  or `n` objects of `U`
111(if `T` is an array type of the form `U[]` and  `n` is determined by
112arguments, as specified by the concrete overload). The object is initialized
113from arguments as specified by the concrete overload. Uses a rebound copy of
114`a` (for an unspecified `value_type`) to allocate memory. If an exception is
115thrown, the functions have no effect.
116
117Returns:: A `shared_ptr` instance that stores and owns the address of the
118newly constructed object.
119
120Postconditions:: `r.get() != 0` and `r.use_count() == 1`, where `r`
121is the return value.
122
123Throws:: `std::bad_alloc`, an exception thrown from `A::allocate`, or from the
124initialization of the object.
125
126Remarks::
127* Performs no more than one memory allocation. This provides efficiency
128equivalent to an intrusive smart pointer.
129* When an object of an array type is specified to be initialized to a value of
130the same type `v`, this shall be interpreted to mean that each array element
131of the object is initialized to the corresponding element from `v`.
132* When an object of an array type is specified to be value-initialized, this
133shall be interpreted to mean that each array element of the object is
134value-initialized.
135* When a (sub)object of non-array type `U` is specified to be initialized to
136a value `v`, or constructed from `args\...`, `make_shared` shall perform
137this initialization via the expression `::new(p) U(expr)` (where
138`_expr_` is `v` or `std::forward<Args>(args)\...)` respectively) and `p`
139has type `void*` and points to storage suitable to hold an object of type
140`U`.
141* When a (sub)object of non-array type `U` is specified to be initialized to
142a value `v`, or constructed from `args\...`, `allocate_shared` shall
143perform this initialization via the expression
144`std::allocator_traits<A2>::construct(a2, p, expr)` (where
145`_expr_` is `v` or `std::forward<Args>(args)\...)` respectively), `p`
146points to storage suitable to hold an object of type `U`, and `a2` of
147type `A2` is a potentially rebound copy of `a`.
148* When a (sub)object of non-array type `U` is specified to be
149default-initialized, `make_shared_noinit` and `allocate_shared_noinit` shall
150perform this initialization via the expression `::new(p) U`, where
151`p` has type `void*` and points to storage suitable to hold an object of
152type `U`.
153* When a (sub)object of non-array type `U` is specified to be
154value-initialized, `make_shared` shall perform this initialization via the
155expression `::new(p) U()`, where `p` has type `void*` and points to
156storage suitable to hold an object of type `U`.
157* When a (sub)object of non-array type `U` is specified to be
158value-initialized, `allocate_shared` shall perform this initialization via the
159expression `std::allocator_traits<A2>::construct(a2, p)`, where
160`p` points to storage suitable to hold an object of type `U` and `a2` of
161type `A2` is a potentially rebound copy of `a`.
162* Array elements are initialized in ascending order of their addresses.
163* When the lifetime of the object managed by the return value ends, or when
164the initialization of an array element throws an exception, the initialized
165elements should be destroyed in the reverse order of their construction.
166
167NOTE: These functions will typically allocate more memory than the total size
168of the element objects to allow for internal bookkeeping structures such as
169the reference counts.
170
171## Free Functions
172
173```
174template<class T, class... Args>
175  shared_ptr<T> make_shared(Args&&... args);
176```
177```
178template<class T, class A, class... Args>
179  shared_ptr<T> allocate_shared(const A& a, Args&&... args);
180```
181[none]
182* {blank}
183+
184Constraints:: `T` is not an array.
185Returns:: A `shared_ptr` to an object of type `T`, constructed from
186`args\...`.
187Examples::
188* `auto p = make_shared<int>();`
189* `auto p = make_shared<std::vector<int> >(16, 1);`
190
191```
192template<class T>
193  shared_ptr<T> make_shared(std::size_t n);
194```
195```
196template<class T, class A>
197  shared_ptr<T> allocate_shared(const A& a, std::size_t n);
198```
199[none]
200* {blank}
201+
202Constraints:: `T` is an array of unknown bounds.
203Returns:: A `shared_ptr` to a sequence of `n` value-initialized objects of
204type `remove_extent_t<T>`.
205Examples::
206* `auto p = make_shared<double[]>(1024);`
207* `auto p = make_shared<double[][2][2]>(6);`
208
209```
210template<class T>
211  shared_ptr<T> make_shared();
212```
213```
214template<class T, class A>
215  shared_ptr<T> allocate_shared(const A& a);
216```
217[none]
218* {blank}
219+
220Constraints:: `T` is an array of known bounds.
221Returns:: A `shared_ptr` to a sequence of `extent_v<T>` value-initialized
222objects of type `remove_extent_t<T>`.
223Examples::
224* `auto p = make_shared<double[1024]>();`
225* `auto p = make_shared<double[6][2][2]>();`
226
227```
228template<class T> shared_ptr<T>
229  make_shared(std::size_t n, const remove_extent_t<T>& v);
230```
231```
232template<class T, class A> shared_ptr<T>
233  allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);
234```
235[none]
236* {blank}
237+
238Constraints:: `T` is an array of unknown bounds.
239Returns:: A `shared_ptr` to a sequence of `n` objects of type
240`remove_extent_t<T>`, each initialized to `v`.
241Examples::
242* `auto p = make_shared<double[]>(1024, 1.0);`
243* `auto p = make_shared<double[][2]>(6, {1.0, 0.0});`
244* `auto p = make_shared<std::vector<int>[]>(4, {1, 2});`
245
246```
247template<class T>
248  shared_ptr<T> make_shared(const remove_extent_t<T>& v);
249```
250```
251template<class T, class A>
252  shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v);
253```
254[none]
255* {blank}
256+
257Constraints:: `T` is an array of known bounds.
258Returns:: A `shared_ptr` to a sequence of `extent_v<T>` objects of type
259`remove_extent_t<T>`, each initialized to `v`.
260Examples::
261* `auto p = make_shared<double[1024]>(1.0);`
262* `auto p = make_shared<double[6][2]>({1.0, 0.0});`
263* `auto p = make_shared<std::vector<int>[4]>({1, 2});`
264
265```
266template<class T>
267  shared_ptr<T> make_shared_noinit();
268```
269```
270template<class T, class A>
271  shared_ptr<T> allocate_shared_noinit(const A& a);
272```
273[none]
274* {blank}
275+
276Constraints:: `T` is not an array, or is an array of known bounds.
277Returns:: A `shared_ptr` to a default-initialized object of type `T`, or a
278sequence of `extent_v<T>` default-initialized objects of type
279`remove_extent_t<T>`, respectively.
280Example:: `auto p = make_shared_noinit<double[1024]>();`
281
282```
283template<class T>
284  shared_ptr<T> make_shared_noinit(std::size_t n);
285```
286```
287template<class T, class A>
288  shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n);
289```
290[none]
291* {blank}
292+
293Constraints:: `T` is an array of unknown bounds.
294Returns:: A `shared_ptr` to a sequence of `_n_` default-initialized objects
295of type `remove_extent_t<T>`.
296Example:: `auto p = make_shared_noinit<double[]>(1024);`
297