• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1////
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 & r) const noexcept;
152
153    // owner_equals
154
155    template<class Y> bool owner_equals(local_shared_ptr<Y> const & r) const noexcept;
156  };
157
158  // comparisons
159
160  template<class T, class U>
161    bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
162  template<class T, class U>
163    bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
164  template<class T, class U>
165    bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
166
167  template<class T, class U>
168    bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
169  template<class T, class U>
170    bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
171  template<class T, class U>
172    bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
173
174  template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
175  template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
176
177  template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
178  template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
179
180  template<class T, class U>
181    bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
182
183  // swap
184
185  template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept;
186
187  // get_pointer
188
189  template<class T>
190    typename local_shared_ptr<T>::element_type *
191      get_pointer(local_shared_ptr<T> const & p) noexcept;
192
193  // casts
194
195  template<class T, class U>
196    local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept;
197
198  template<class T, class U>
199    local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept;
200
201  template<class T, class U>
202    local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept;
203
204  template<class T, class U>
205    local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept;
206
207  // stream I/O
208
209  template<class E, class T, class Y>
210    std::basic_ostream<E, T> &
211      operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p);
212
213  // get_deleter
214
215  template<class D, class T> D * get_deleter(local_shared_ptr<T> const & p) noexcept;
216}
217```
218
219## Members
220
221### element_type
222```
223typedef ... element_type;
224```
225`element_type` is `T` when `T` is not an array type, and `U` when `T` is `U[]` or `U[N]`.
226
227### default constructor
228```
229constexpr local_shared_ptr() noexcept;
230```
231```
232constexpr local_shared_ptr(std::nullptr_t) noexcept;
233```
234[none]
235* {blank}
236+
237Effects:: Constructs an empty `local_shared_ptr`.
238Postconditions:: `local_use_count() == 0 && get() == 0`.
239
240### pointer constructor
241```
242template<class Y> explicit local_shared_ptr(Y * p);
243```
244[none]
245* {blank}
246+
247Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p )`.
248
249Postconditions:: `local_use_count() == 1 && get() == p`.
250
251Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
252
253### constructors taking a deleter
254```
255template<class Y, class D> local_shared_ptr(Y * p, D d);
256```
257```
258template<class D> local_shared_ptr(std::nullptr_t p, D d);
259```
260[none]
261* {blank}
262+
263Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p, d )`.
264
265Postconditions:: `local_use_count() == 1 && get() == p`.
266
267Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
268
269```
270template<class Y, class D, class A> local_shared_ptr(Y * p, D d, A a);
271```
272```
273template<class D, class A> local_shared_ptr(std::nullptr_t p, D d, A a);
274```
275[none]
276* {blank}
277+
278Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr<T>( p, d, a )`.
279
280Postconditions:: `local_use_count() == 1 && get() == p`.
281
282Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
283
284### copy and converting constructors
285```
286local_shared_ptr(local_shared_ptr const & r) noexcept;
287```
288```
289template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r) noexcept;
290```
291[none]
292* {blank}
293+
294Requires:: `Y*` should be convertible to `T*`.
295
296Effects:: If `r` is empty, constructs an empty `local_shared_ptr`; otherwise, constructs a `local_shared_ptr` that shares ownership with `r`.
297
298Postconditions:: `get() == r.get() && local_use_count() == r.local_use_count()`.
299
300### move constructors
301```
302local_shared_ptr(local_shared_ptr && r) noexcept;
303```
304```
305template<class Y> local_shared_ptr(local_shared_ptr<Y> && r) noexcept;
306```
307[none]
308* {blank}
309+
310Requires:: `Y*` should be convertible to `T*`.
311
312Effects:: Move-constructs a `local_shared_ptr` from `r`.
313
314Postconditions:: `*this` contains the old value of `r`. `r` is empty and `r.get() == 0`.
315
316### shared_ptr constructor
317```
318template<class Y> local_shared_ptr( shared_ptr<Y> const & r );
319```
320```
321template<class Y> local_shared_ptr( shared_ptr<Y> && r );
322```
323[none]
324* {blank}
325+
326Effects:: Constructs a `local_shared_ptr` that owns `r`.
327
328Postconditions:: `local_use_count() == 1`. `get()` returns the old value of `r.get()`.
329
330Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
331
332### aliasing constructor
333```
334template<class Y> local_shared_ptr(local_shared_ptr<Y> const & r, element_type * p) noexcept;
335```
336[none]
337* {blank}
338+
339Effects:: constructs a `local_shared_ptr` that shares ownership with `r` and stores `p`.
340
341Postconditions:: `get() == p && local_use_count() == r.local_use_count()`.
342
343### aliasing move constructor
344```
345template<class Y> local_shared_ptr(local_shared_ptr<Y> && r, element_type * p) noexcept;
346```
347[none]
348* {blank}
349+
350Effects:: Move-constructs a `local_shared_ptr` from `r`, while storing `p` instead.
351
352Postconditions:: `get() == p` and `local_use_count()` equals the old count of `r`. `r` is empty and `r.get() == 0`.
353
354### unique_ptr constructor
355```
356template<class Y, class D> local_shared_ptr(std::unique_ptr<Y, D> && r);
357```
358[none]
359* {blank}
360+
361Requires:: `Y*` should be convertible to `T*`.
362
363Effects::
364- When `r.get() == 0`, equivalent to `local_shared_ptr()`;
365- Otherwise, constructs a `local_shared_ptr` that owns `shared_ptr<T>( std::move(r) )`.
366
367Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained.
368
369Exception safety:: If an exception is thrown, the constructor has no effect.
370
371### destructor
372```
373~local_shared_ptr() noexcept;
374```
375[none]
376* {blank}
377+
378Effects::
379- If `*this` is empty, or shares ownership with another `local_shared_ptr` instance (`local_use_count() > 1`), there are no side effects.
380- Otherwise, destroys the owned `shared_ptr`.
381
382### assignment
383```
384local_shared_ptr & operator=(local_shared_ptr const & r) noexcept;
385```
386```
387template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> const & r) noexcept;
388```
389[none]
390* {blank}
391+
392Effects:: Equivalent to `local_shared_ptr(r).swap(*this)`.
393Returns:: `*this`.
394
395```
396local_shared_ptr & operator=(local_shared_ptr && r) noexcept;
397```
398```
399template<class Y> local_shared_ptr & operator=(local_shared_ptr<Y> && r) noexcept;
400```
401```
402template<class Y, class D> local_shared_ptr & operator=(std::unique_ptr<Y, D> && r);
403```
404[none]
405* {blank}
406+
407Effects:: Equivalent to `local_shared_ptr(std::move(r)).swap(*this)`.
408Returns:: `*this`.
409
410```
411local_shared_ptr & operator=(std::nullptr_t) noexcept;
412```
413[none]
414* {blank}
415+
416Effects:: Equivalent to `local_shared_ptr().swap(*this)`.
417Returns:: `*this`.
418
419### reset
420```
421void reset() noexcept;
422```
423[none]
424* {blank}
425+
426Effects:: Equivalent to `local_shared_ptr().swap(*this)`.
427
428```
429template<class Y> void reset(Y * p);
430```
431[none]
432* {blank}
433+
434Effects:: Equivalent to `local_shared_ptr(p).swap(*this)`.
435
436```
437template<class Y, class D> void reset(Y * p, D d);
438```
439[none]
440* {blank}
441+
442Effects:: Equivalent to `local_shared_ptr(p, d).swap(*this)`.
443
444```
445template<class Y, class D, class A> void reset(Y * p, D d, A a);
446```
447[none]
448* {blank}
449+
450Effects:: Equivalent to `local_shared_ptr(p, d, a).swap(*this)`.
451
452```
453template<class Y> void reset(local_shared_ptr<Y> const & r, element_type * p) noexcept;
454```
455[none]
456* {blank}
457+
458Effects:: Equivalent to `local_shared_ptr(r, p).swap(*this)`.
459
460```
461template<class Y> void reset(local_shared_ptr<Y> && r, element_type * p) noexcept;
462```
463[none]
464* {blank}
465+
466Effects::
467  Equivalent to `local_shared_ptr(std::move(r), p).swap(*this)`.
468
469### indirection
470```
471T & operator*() const noexcept;
472```
473[none]
474* {blank}
475+
476Requires:: `T` should not be an array type.
477Returns:: `*get()`.
478
479```
480T * operator->() const noexcept;
481```
482[none]
483* {blank}
484+
485Requires:: `T` should not be an array type.
486Returns:: `get()`.
487
488```
489element_type & operator[](std::ptrdiff_t i) const noexcept;
490```
491[none]
492* {blank}
493+
494Requires:: `T` should be an array type. The stored pointer must not be 0. `i >= 0`. If `T` is `U[N]`, `i < N`.
495Returns:: `get()[i]`.
496
497### get
498
499```
500element_type * get() const noexcept;
501```
502[none]
503* {blank}
504+
505Returns::
506  The stored pointer.
507
508### local_use_count
509```
510long local_use_count() const noexcept;
511```
512[none]
513* {blank}
514+
515Returns::
516  The number of `local_shared_ptr` objects, `*this` included, that share ownership with `*this`, or 0 when `*this` is empty.
517
518### conversions
519```
520explicit operator bool() const noexcept;
521```
522[none]
523* {blank}
524+
525Returns:: `get() != 0`.
526
527NOTE: On C++03 compilers, the return value is of an unspecified type.
528
529```
530template<class Y> operator shared_ptr<Y>() const noexcept;
531```
532```
533template<class Y> operator weak_ptr<Y>() const noexcept;
534```
535[none]
536* {blank}
537+
538Requires:: `T*` should be convertible to `Y*`.
539Returns:: a copy of the owned `shared_ptr`.
540
541### swap
542```
543void swap(local_shared_ptr & b) noexcept;
544```
545[none]
546* {blank}
547+
548Effects::
549  Exchanges the contents of the two smart pointers.
550
551### owner_before
552```
553template<class Y> bool owner_before(local_shared_ptr<Y> const & r) const noexcept;
554```
555[none]
556* {blank}
557+
558Returns::
559  See the description of `operator<`.
560
561### owner_equals
562```
563template<class Y> bool owner_equals(local_shared_ptr<Y> const & r) const noexcept;
564```
565[none]
566* {blank}
567+
568Returns::
569  `true` if and only if `*this` and `r` share ownership or are both empty.
570
571## Free Functions
572
573### comparison
574```
575template<class T, class U>
576  bool operator==(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
577```
578```
579template<class T, class U>
580  bool operator==(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
581```
582```
583template<class T, class U>
584  bool operator==(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
585```
586[none]
587* {blank}
588+
589Returns:: `a.get() == b.get()`.
590
591```
592template<class T, class U>
593  bool operator!=(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
594```
595```
596template<class T, class U>
597  bool operator!=(local_shared_ptr<T> const & a, shared_ptr<U> const & b) noexcept;
598```
599```
600template<class T, class U>
601  bool operator!=(shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
602```
603[none]
604* {blank}
605+
606Returns:: `a.get() != b.get()`.
607
608```
609template<class T> bool operator==(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
610```
611```
612template<class T> bool operator==(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
613```
614[none]
615* {blank}
616+
617Returns:: `p.get() == 0`.
618
619```
620template<class T> bool operator!=(local_shared_ptr<T> const & p, std::nullptr_t) noexcept;
621```
622```
623template<class T> bool operator!=(std::nullptr_t, local_shared_ptr<T> const & p) noexcept;
624```
625[none]
626* {blank}
627+
628Returns:: `p.get() != 0`.
629
630```
631template<class T, class U>
632  bool operator<(local_shared_ptr<T> const & a, local_shared_ptr<U> const & b) noexcept;
633```
634[none]
635* {blank}
636+
637Returns:: An unspecified value such that
638  - `operator<` is a strict weak ordering as described in section [lib.alg.sorting] of the {cpp} standard;
639  - under the equivalence relation defined by `operator<`, `!(a < b) && !(b < a)`, two `local_shared_ptr` instances
640    are equivalent if and only if they share ownership or are both empty.
641
642NOTE: Allows `local_shared_ptr` objects to be used as keys in associative containers.
643
644NOTE: The rest of the comparison operators are omitted by design.
645
646### swap
647```
648template<class T> void swap(local_shared_ptr<T> & a, local_shared_ptr<T> & b) noexcept;
649```
650[none]
651* {blank}
652+
653Effects::
654  Equivalent to `a.swap(b)`.
655
656### get_pointer
657```
658template<class T>
659  typename local_shared_ptr<T>::element_type *
660    get_pointer(local_shared_ptr<T> const & p) noexcept;
661```
662[none]
663* {blank}
664+
665Returns:: `p.get()`.
666
667NOTE: Provided as an aid to generic programming. Used by `mem_fn`.
668
669### static_pointer_cast
670```
671template<class T, class U>
672  local_shared_ptr<T> static_pointer_cast(local_shared_ptr<U> const & r) noexcept;
673```
674[none]
675* {blank}
676+
677Requires:: The expression `static_cast<T*>( (U*)0 )` must be well-formed.
678Returns:: `local_shared_ptr<T>( r, static_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
679
680CAUTION: The seemingly equivalent expression `local_shared_ptr<T>(static_cast<T*>(r.get()))` will eventually
681result in undefined behavior, attempting to delete the same object twice.
682
683### const_pointer_cast
684```
685template<class T, class U>
686  local_shared_ptr<T> const_pointer_cast(local_shared_ptr<U> const & r) noexcept;
687```
688[none]
689* {blank}
690+
691Requires:: The expression `const_cast<T*>( (U*)0 )` must be well-formed.
692Returns:: `local_shared_ptr<T>( r, const_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
693
694### dynamic_pointer_cast
695```
696template<class T, class U>
697    local_shared_ptr<T> dynamic_pointer_cast(local_shared_ptr<U> const & r) noexcept;
698```
699[none]
700* {blank}
701+
702Requires:: The expression `dynamic_cast<T*>( (U*)0 )` must be well-formed.
703Returns::
704  - When `dynamic_cast<typename local_shared_ptr<T>::element_type*>(r.get())` returns a nonzero value `p`, `local_shared_ptr<T>(r, p)`;
705  - Otherwise, `local_shared_ptr<T>()`.
706
707### reinterpret_pointer_cast
708```
709template<class T, class U>
710  local_shared_ptr<T> reinterpret_pointer_cast(local_shared_ptr<U> const & r) noexcept;
711```
712[none]
713* {blank}
714+
715Requires:: The expression `reinterpret_cast<T*>( (U*)0 )` must be well-formed.
716Returns:: `local_shared_ptr<T>( r, reinterpret_cast<typename local_shared_ptr<T>::element_type*>(r.get()) )`.
717
718### operator<<
719```
720template<class E, class T, class Y>
721  std::basic_ostream<E, T> &
722    operator<< (std::basic_ostream<E, T> & os, local_shared_ptr<Y> const & p);
723```
724[none]
725* {blank}
726+
727Effects:: `os << p.get();`.
728Returns:: `os`.
729
730### get_deleter
731```
732template<class D, class T>
733  D * get_deleter(local_shared_ptr<T> const & p) noexcept;
734```
735[none]
736* {blank}
737+
738Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter<D>( p )`, otherwise 0.
739