blob: d7d34dd19ddfd536ff9d2156094fdb5928ef42f2 [file] [log] [blame]
Brian Silverman355f11d2018-08-04 23:57:00 -07001////
2Copyright 2017 Peter Dimov
3
4Distributed under the Boost Software License, Version 1.0.
5
6See accompanying file LICENSE_1_0.txt or copy at
7http://www.boost.org/LICENSE_1_0.txt
8////
9
10[#local_shared_ptr]
11# local_shared_ptr: Shared Ownership within a Single Thread
12:toc:
13:toc-title:
14:idprefix: local_shared_ptr_
15
16## Description
17
18`local_shared_ptr` is nearly identical to `shared_ptr`, with the only difference of note being that its reference count is
19updated with non-atomic operations. As such, a `local_shared_ptr` and all its copies must reside in (be local to) a single
20thread (hence the name.)
21
22`local_shared_ptr` can be converted to `shared_ptr` and vice versa. Creating a `local_shared_ptr` from a `shared_ptr` creates
23a new local reference count; this means that two `local_shared_ptr` instances, both created from the same `shared_ptr`, refer
24to the same object but don't share the same count, and as such, can safely be used by two different threads.
25
26.Two local_shared_ptr instances created from a shared_ptr
27```
28shared_ptr<X> p1( new X );
29
30local_shared_ptr<X> p2( p1 ); // p2.local_use_count() == 1
31local_shared_ptr<X> p3( p1 ); // p3.local_use_count() also 1
32```
33
34Creating the second `local_shared_ptr` from the first one, however, does lead to the two sharing the same count:
35
36.A local_shared_ptr created from another local_shared_ptr
37```
38shared_ptr<X> p1( new X );
39
40local_shared_ptr<X> p2( p1 ); // p2.local_use_count() == 1
41local_shared_ptr<X> p3( p2 ); // p3.local_use_count() == 2
42```
43
44Two `shared_ptr` instances created from the same `local_shared_ptr` do share ownership:
45
46.Two shared_ptr instances created from a local_shared_ptr
47```
48local_shared_ptr<X> p1( new X );
49
50shared_ptr<X> p2( p1 ); // p2.use_count() == 2
51shared_ptr<X> p3( p1 ); // p3.use_count() == 3
52```
53
54Here `p2.use_count()` is 2, because `p1` holds a reference, too.
55
56One can think of `local_shared_ptr<T>` as `shared_ptr<shared_ptr<T>>`, with the outer `shared_ptr` using non-atomic operations for
57its count. Converting from `local_shared_ptr` to `shared_ptr` gives you a copy of the inner `shared_ptr`; converting from `shared_ptr`
58wraps it into an outer `shared_ptr` with a non-atomic use count (conceptually speaking) and returns the result.
59
60## Synopsis
61
62`local_shared_ptr` is defined in `<boost/smart_ptr/local_shared_ptr.hpp>`.
63
64```
65namespace boost {
66
67 template<class T> class local_shared_ptr {
68 public:
69
70 typedef /*see below*/ element_type;
71
72 // constructors
73
74 constexpr local_shared_ptr() noexcept;
75 constexpr local_shared_ptr(std::nullptr_t) noexcept;
76
77 template<class Y> explicit local_shared_ptr(Y * p);
78
79 template<class Y, class D> local_shared_ptr(Y * p, D d);
80 template<class D> local_shared_ptr(std::nullptr_t p, D d);
81
82 template<class Y, class D, class A> local_shared_ptr(Y * p, D d, A a);
83 template<class D, class A> local_shared_ptr(std::nullptr_t p, D d, A a);
84
85 local_shared_ptr(local_shared_ptr const & r) noexcept;
86 template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r) noexcept;
87
88 local_shared_ptr(local_shared_ptr && r) noexcept;
89 template<class Y> local_shared_ptr(local_shared_ptr<Y> && r) noexcept;
90
91 template<class Y> local_shared_ptr( shared_ptr<Y> const & r );
92 template<class Y> local_shared_ptr( shared_ptr<Y> && r );
93
94 template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r, element_type * p) noexcept;
95 template<class Y> local_shared_ptr(local_shared_ptr<Y> && r, element_type * p) noexcept;
96
97 template<class Y, class D> local_shared_ptr(std::unique_ptr<Y, D> && r);
98
99 // destructor
100
101 ~local_shared_ptr() noexcept;
102
103 // assignment
104
105 local_shared_ptr & operator=(local_shared_ptr const & r) noexcept;
106 template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const & r) noexcept;
107
108 local_shared_ptr & operator=(local_shared_ptr const && r) noexcept;
109 template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const && r) noexcept;
110
111 template<class Y, class D> local_shared_ptr & operator=(std::unique_ptr<Y, D> && r);
112
113 local_shared_ptr & operator=(std::nullptr_t) noexcept;
114
115 // reset
116
117 void reset() noexcept;
118
119 template<class Y> void reset(Y * p);
120 template<class Y, class D> void reset(Y * p, D d);
121 template<class Y, class D, class A> void reset(Y * p, D d, A a);
122
123 template<class Y> void reset(local_shared_ptr<Y> const & r, element_type * p) noexcept;
124 template<class Y> void reset(local_shared_ptr<Y> && r, element_type * p) noexcept;
125
126 // accessors
127
128 T & operator*() const noexcept; // only valid when T is not an array type
129 T * operator->() const noexcept; // only valid when T is not an array type
130
131 // only valid when T is an array type
132 element_type & operator[](std::ptrdiff_t i) const noexcept;
133
134 element_type * get() const noexcept;
135
136 long local_use_count() const noexcept;
137
138 // conversions
139
140 explicit operator bool() const noexcept;
141
142 template<class Y> operator shared_ptr<Y>() const noexcept;
143 template<class Y> operator weak_ptr<Y>() const noexcept;
144
145 // swap
146
147 void swap(local_shared_ptr & b) noexcept;
148
149 // owner_before
150
151 template<class Y> bool owner_before(local_shared_ptr<Y> const & rhs) const noexcept;
152 };
153
154 // comparisons
155
156 template<class T, class U>
157 bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
158 template<class T, class U>
159 bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
160 template<class T, class U>
161 bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
162
163 template<class T, class U>
164 bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
165 template<class T, class U>
166 bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
167 template<class T, class U>
168 bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
169
170 template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
171 template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
172
173 template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
174 template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
175
176 template<class T, class U>
177 bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
178
179 // swap
180
181 template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept;
182
183 // get_pointer
184
185 template<class T>
186 typename local_shared_ptr<T>::element_type *
187 get_pointer(local_shared_ptr<T> const & p) noexcept;
188
189 // casts
190
191 template<class T, class U>
192 local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept;
193
194 template<class T, class U>
195 local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept;
196
197 template<class T, class U>
198 local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept;
199
200 template<class T, class U>
201 local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept;
202
203 // stream I/O
204
205 template<class E, class T, class Y>
206 std::basic_ostream<E, T> &
207 operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p);
208
209 // get_deleter
210
211 template<class D, class T> D * get_deleter(local_shared_ptr<T> const & p) noexcept;
212}
213```
214
215## Members
216
217### element_type
218```
219typedef ... element_type;
220```
221`element_type` is `T` when `T` is not an array type, and `U` when `T` is `U[]` or `U[N]`.
222
223### default constructor
224```
225constexpr local_shared_ptr() noexcept;
226```
227```
228constexpr local_shared_ptr(std::nullptr_t) noexcept;
229```
230[none]
231* {blank}
232+
233Effects:: Constructs an empty `local_shared_ptr`.
234Postconditions:: `local_use_count() == 0 && get() == 0`.
235
236### pointer constructor
237```
238template<class Y> explicit local_shared_ptr(Y * p);
239```
240[none]
241* {blank}
242+
243Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p )`.
244
245Postconditions:: `local_use_count() == 1 && get() == p`.
246
247Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
248
249### constructors taking a deleter
250```
251template<class Y, class D> local_shared_ptr(Y * p, D d);
252```
253```
254template<class D> local_shared_ptr(std::nullptr_t p, D d);
255```
256[none]
257* {blank}
258+
259Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p, d )`.
260
261Postconditions:: `local_use_count() == 1 && get() == p`.
262
263Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
264
265```
266template<class Y, class D, class A> local_shared_ptr(Y * p, D d, A a);
267```
268```
269template<class D, class A> local_shared_ptr(std::nullptr_t p, D d, A a);
270```
271[none]
272* {blank}
273+
274Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p, d, a )`.
275
276Postconditions:: `local_use_count() == 1 && get() == p`.
277
278Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
279
280### copy and converting constructors
281```
282local_shared_ptr(local_shared_ptr const & r) noexcept;
283```
284```
285template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r) noexcept;
286```
287[none]
288* {blank}
289+
290Requires:: `Y*` should be convertible to `T*`.
291
292Effects:: If `r` is empty, constructs an empty `local_shared_ptr`; otherwise, constructs a `local_shared_ptr` that shares ownership with `r`.
293
294Postconditions:: `get() == r.get() && local_use_count() == r.local_use_count()`.
295
296### move constructors
297```
298local_shared_ptr(local_shared_ptr && r) noexcept;
299```
300```
301template<class Y> local_shared_ptr(local_shared_ptr<Y> && r) noexcept;
302```
303[none]
304* {blank}
305+
306Requires:: `Y*` should be convertible to `T*`.
307
308Effects:: Move-constructs a `local_shared_ptr` from `r`.
309
310Postconditions:: `*this` contains the old value of `r`. `r` is empty and `r.get() == 0`.
311
312### shared_ptr constructor
313```
314template<class Y> local_shared_ptr( shared_ptr<Y> const & r );
315```
316```
317template<class Y> local_shared_ptr( shared_ptr<Y> && r );
318```
319[none]
320* {blank}
321+
322Effects:: Constructs a `local_shared_ptr` that owns `r`.
323
324Postconditions:: `local_use_count() == 1`. `get()` returns the old value of `r.get()`.
325
326Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
327
328### aliasing constructor
329```
330template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r, element_type * p) noexcept;
331```
332[none]
333* {blank}
334+
335Effects:: constructs a `local_shared_ptr` that shares ownership with `r` and stores `p`.
336
337Postconditions:: `get() == p && local_use_count() == r.local_use_count()`.
338
339### aliasing move constructor
340```
341template<class Y> local_shared_ptr(local_shared_ptr<Y> && r, element_type * p) noexcept;
342```
343[none]
344* {blank}
345+
346Effects:: Move-constructs a `local_shared_ptr` from `r`, while storing `p` instead.
347
348Postconditions:: `get() == p` and `local_use_count()` equals the old count of `r`. `r` is empty and `r.get() == 0`.
349
350### unique_ptr constructor
351```
352template<class Y, class D> local_shared_ptr(std::unique_ptr<Y, D> && r);
353```
354[none]
355* {blank}
356+
357Requires:: `Y*` should be convertible to `T*`.
358
359Effects::
360- When `r.get() == 0`, equivalent to `local_shared_ptr()`;
361- Otherwise, constructs a `local_shared_ptr` that owns `shared_ptr<T>( std::move(r) )`.
362
363Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
364
365Exception safety:: If an exception is thrown, the constructor has no effect.
366
367### destructor
368```
369~local_shared_ptr() noexcept;
370```
371[none]
372* {blank}
373+
374Effects::
375- If `*this` is empty, or shares ownership with another `local_shared_ptr` instance (`local_use_count() > 1`), there are no side effects.
376- Otherwise, destroys the owned `shared_ptr`.
377
378### assignment
379```
380local_shared_ptr & operator=(local_shared_ptr const & r) noexcept;
381```
382```
383template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const & r) noexcept;
384```
385[none]
386* {blank}
387+
388Effects:: Equivalent to `local_shared_ptr(r).swap(*this)`.
389Returns:: `*this`.
390
391```
392local_shared_ptr & operator=(local_shared_ptr && r) noexcept;
393```
394```
395template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> && r) noexcept;
396```
397```
398template<class Y, class D> local_shared_ptr & operator=(std::unique_ptr<Y, D> && r);
399```
400[none]
401* {blank}
402+
403Effects:: Equivalent to `local_shared_ptr(std::move(r)).swap(*this)`.
404Returns:: `*this`.
405
406```
407local_shared_ptr & operator=(std::nullptr_t) noexcept;
408```
409[none]
410* {blank}
411+
412Effects:: Equivalent to `local_shared_ptr().swap(*this)`.
413Returns:: `*this`.
414
415### reset
416```
417void reset() noexcept;
418```
419[none]
420* {blank}
421+
422Effects:: Equivalent to `local_shared_ptr().swap(*this)`.
423
424```
425template<class Y> void reset(Y * p);
426```
427[none]
428* {blank}
429+
430Effects:: Equivalent to `local_shared_ptr(p).swap(*this)`.
431
432```
433template<class Y, class D> void reset(Y * p, D d);
434```
435[none]
436* {blank}
437+
438Effects:: Equivalent to `local_shared_ptr(p, d).swap(*this)`.
439
440```
441template<class Y, class D, class A> void reset(Y * p, D d, A a);
442```
443[none]
444* {blank}
445+
446Effects:: Equivalent to `local_shared_ptr(p, d, a).swap(*this)`.
447
448```
449template<class Y> void reset(local_shared_ptr<Y> const & r, element_type * p) noexcept;
450```
451[none]
452* {blank}
453+
454Effects:: Equivalent to `local_shared_ptr(r, p).swap(*this)`.
455
456```
457template<class Y> void reset(local_shared_ptr<Y> && r, element_type * p) noexcept;
458```
459[none]
460* {blank}
461+
462Effects:: Equivalent to `local_shared_ptr(std::move(r), p).swap(*this)`.
463
464### indirection
465```
466T & operator*() const noexcept;
467```
468[none]
469* {blank}
470+
471Requires:: `T` should not be an array type.
472Returns:: `*get()`.
473
474```
475T * operator->() const noexcept;
476```
477[none]
478* {blank}
479+
480Requires:: `T` should not be an array type.
481Returns:: `get()`.
482
483```
484element_type & operator[](std::ptrdiff_t i) const noexcept;
485```
486[none]
487* {blank}
488+
489Requires:: `T` should be an array type. The stored pointer must not be 0. `i >= 0`. If `T` is `U[N]`, `i < N`.
490Returns:: `get()[i]`.
491
492### get
493
494```
495element_type * get() const noexcept;
496```
497[none]
498* {blank}
499+
500Returns:: The stored pointer.
501
502### local_use_count
503```
504long local_use_count() const noexcept;
505```
506[none]
507* {blank}
508+
509Returns:: The number of `local_shared_ptr` objects, `*this` included, that share ownership with `*this`, or 0 when `*this` is empty.
510
511### conversions
512```
513explicit operator bool() const noexcept;
514```
515[none]
516* {blank}
517+
518Returns:: `get() != 0`.
519
520NOTE: On C++03 compilers, the return value is of an unspecified type.
521
522```
523template<class Y> operator shared_ptr<Y>() const noexcept;
524```
525```
526template<class Y> operator weak_ptr<Y>() const noexcept;
527```
528[none]
529* {blank}
530+
531Requires:: `T*` should be convertible to `Y*`.
532Returns:: a copy of the owned `shared_ptr`.
533
534### swap
535```
536void swap(local_shared_ptr & b) noexcept;
537```
538[none]
539* {blank}
540+
541Effects:: Exchanges the contents of the two smart pointers.
542
543### owner_before
544```
545template<class Y> bool owner_before(local_shared_ptr<Y> const & rhs) const noexcept;
546```
547[none]
548* {blank}
549+
550Effects:: See the description of `operator<`.
551
552## Free Functions
553
554### comparison
555```
556template<class T, class U>
557 bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
558```
559```
560template<class T, class U>
561 bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
562```
563```
564template<class T, class U>
565 bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
566```
567[none]
568* {blank}
569+
570Returns:: `a.get() == b.get()`.
571
572```
573template<class T, class U>
574 bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
575```
576```
577template<class T, class U>
578 bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
579```
580```
581template<class T, class U>
582 bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
583```
584[none]
585* {blank}
586+
587Returns:: `a.get() != b.get()`.
588
589```
590template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
591```
592```
593template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
594```
595[none]
596* {blank}
597+
598Returns:: `p.get() == 0`.
599
600```
601template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
602```
603```
604template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
605```
606[none]
607* {blank}
608+
609Returns:: `p.get() != 0`.
610
611```
612template<class T, class U>
613 bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
614```
615[none]
616* {blank}
617+
618Returns:: An unspecified value such that
619 - `operator<` is a strict weak ordering as described in section [lib.alg.sorting] of the {cpp} standard;
620 - under the equivalence relation defined by `operator<`, `!(a < b) && !(b < a)`, two `local_shared_ptr` instances
621 are equivalent if and only if they share ownership or are both empty.
622
623NOTE: Allows `local_shared_ptr` objects to be used as keys in associative containers.
624
625NOTE: The rest of the comparison operators are omitted by design.
626
627### swap
628```
629template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept;
630```
631[none]
632* {blank}
633+
634Effects:: Equivalent to `a.swap(b)`.
635
636### get_pointer
637```
638template<class T>
639 typename local_shared_ptr<T>::element_type *
640 get_pointer(local_shared_ptr<T> const & p) noexcept;
641```
642[none]
643* {blank}
644+
645Returns:: `p.get()`.
646
647NOTE: Provided as an aid to generic programming. Used by `mem_fn`.
648
649### static_pointer_cast
650```
651template<class T, class U>
652 local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept;
653```
654[none]
655* {blank}
656+
657Requires:: The expression `static_cast<T*>( (U*)0 )` must be well-formed.
658Returns:: `local_shared_ptr<T>( r, static_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
659
660CAUTION: The seemingly equivalent expression `local_shared_ptr<T>(static_cast<T*>(r.get()))` will eventually
661result in undefined behavior, attempting to delete the same object twice.
662
663### const_pointer_cast
664```
665template<class T, class U>
666 local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept;
667```
668[none]
669* {blank}
670+
671Requires:: The expression `const_cast<T*>( (U*)0 )` must be well-formed.
672Returns:: `local_shared_ptr<T>( r, const_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
673
674### dynamic_pointer_cast
675```
676template<class T, class U>
677 local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept;
678```
679[none]
680* {blank}
681+
682Requires:: The expression `dynamic_cast<T*>( (U*)0 )` must be well-formed.
683Returns::
684 - When `dynamic_cast<typename local_shared_ptr<T>::element_type*>(r.get())` returns a nonzero value `p`, `local_shared_ptr<T>(r, p)`;
685 - Otherwise, `local_shared_ptr<T>()`.
686
687### reinterpret_pointer_cast
688```
689template<class T, class U>
690 local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept;
691```
692[none]
693* {blank}
694+
695Requires:: The expression `reinterpret_cast<T*>( (U*)0 )` must be well-formed.
696Returns:: `local_shared_ptr<T>( r, reinterpret_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
697
698### operator<<
699```
700template<class E, class T, class Y>
701 std::basic_ostream<E, T> &
702 operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p);
703```
704[none]
705* {blank}
706+
707Effects:: `os << p.get();`.
708Returns:: `os`.
709
710### get_deleter
711```
712template<class D, class T>
713 D * get_deleter(local_shared_ptr<T> const & p) noexcept;
714```
715[none]
716* {blank}
717+
718Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter<D>( p )`, otherwise 0.
719