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