// bslstl_sharedptr.h -*-C++-*- #ifndef INCLUDED_BSLSTL_SHAREDPTR #define INCLUDED_BSLSTL_SHAREDPTR #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide a generic reference-counted shared pointer wrapper. // //@CLASSES: // bsl::enable_shared_from_this: base class to allow shared ownership of self // bsl::shared_ptr: shared pointer // bsl::weak_ptr: "weak" reference to reference-counted shared object // bslstl::SharedPtrUtil: shared pointer utility functions // bslstl::SharedPtrNilDeleter: no-op deleter // //@CANONICAL_HEADER: bsl_memory.h // //@SEE_ALSO: bslma_managedptr, bslma_sharedptrrep // //@DESCRIPTION: This component implements a thread-safe, generic, // reference-counted "smart pointer" to support "shared ownership" of objects // of (template parameter) 'ELEMENT_TYPE'. Shared pointers implement a form of // the "envelope/letter" idiom. For each shared object, a representation that // manages the number of references to it is created. Many shared pointers can // simultaneously refer to the same shared object by storing a reference to the // same representation. Shared pointers also implement the "construction is // acquisition, destruction is release" idiom. When a shared pointer is // created it increments the number of shared references to the shared object // that was specified to its constructor (or was referred to by a shared // pointer passed to the copy constructor). When a shared pointer is assigned // to or destroyed, then the number of shared references to the shared object // is decremented. When all references to the shared object are released, both // the representation and the object are destroyed. 'bsl::shared_ptr' emulates // the interface of a native pointer. The shared object may be accessed // directly using the '->' operator, or the dereference operator (operator '*') // can be used to obtain a reference to the shared object. // // This component also provides a mechanism, 'bsl::weak_ptr', used to create // weak references to reference-counted shared ('bsl::shared_ptr') objects. A // weak reference provides conditional access to a shared object managed by a // 'bsl::shared_ptr', but, unlike a shared (or "strong") reference, does not // affect the shared object's lifetime. An object having even one shared // reference to it will not be destroyed, but an object having only weak // references would have been destroyed when the last shared reference was // released. // // A weak pointer can be constructed from another weak pointer or a // 'bsl::shared_ptr'. To access the shared object referenced by a weak pointer // clients must first obtain a shared pointer to that object using the 'lock' // method. If the shared object has been destroyed (as indicated by the // 'expired' method), then 'lock' returns a shared pointer in the default // constructed (empty) state. // // This component also provides a mechanism, 'bsl::enable_shared_from_this', // which can be used to create a type that participates in its own ownership // through the reference-counting of a 'shared_ptr'. // // This component also provides a functor, 'bslstl::SharedPtrNilDeleter', which // may used to create a shared pointer that takes no action when the last // shared reference is destroyed. // // This component also provides a utility class, 'bslstl::SharedPtrUtil', which // provides several functions that are frequently used with shared pointers. // // ///Thread Safety ///------------- // This section qualifies the thread safety of 'bsl::shared_ptr' objects and // 'bsl::weak_ptr' objects themselves rather than the thread safety of the // objects being referenced. // // It is *not* *safe* to access or modify a 'bsl::shared_ptr' (or // 'bsl::weak_ptr') object in one thread while another thread modifies the same // object. However, it is safe to access or modify two distinct 'shared_ptr' // (or 'bsl::weak_ptr') objects simultaneously, each from a separate thread, // even if they share ownership of a common object. It is safe to access a // single 'bsl::shared_ptr' (or 'bsl::weak_ptr') object simultaneously from two // or more separate threads, provided no other thread is simultaneously // modifying the object. // // It is safe to access, modify, copy, or delete a shared pointer (or weak // pointer) in one thread, while other threads access or modify other shared // pointers and weak pointers pointing to or managing the same object (the // reference count is managed using atomic operations). However, there is no // guarantee regarding the safety of accessing or modifying the object // *referred* *to* by the shared pointer simultaneously from multiple threads. // ///Shared and Weak References ///-------------------------- // There are two types of references to shared objects: // // 1) A shared reference allows users to share the ownership of an object and // control its lifetime. A shared object is destroyed only when the last // shared reference to it is released. A shared reference to an object can be // obtained by creating a 'shared_ptr' referring to it. // // 2) A weak reference provides users conditional access to an object without // sharing its ownership (or affecting its lifetime). A shared object can be // destroyed even if there are weak references to it. A weak reference to an // object can be obtained by creating a 'weak_ptr' referring to the object from // a 'shared_ptr' referring to that object. // ///In-place/Out-of-place Representations ///------------------------------------- // 'shared_ptr' provides two types of representations: an out-of-place // representation, and an in-place representation. Out-of-place // representations are used to refer to objects that are constructed externally // to their associated representations. Out-of-place objects are provided to a // shared pointer by passing their address along with the deleter that should // be used to destroy the object when all references to it have been released. // In-place objects can be constructed directly within a shared pointer // representation (see 'createInplace'). // // Below we provide a diagram illustrating the differences between the two // representations for a shared pointer to an 'int'. First we create an 'int' // object on the heap, initialized to 10, and pass its address to a shared // pointer constructor, resulting in an out-of-place representation for the // shared object: //.. // bslma::NewDeleteAllocator nda; // int *value = new (nda) int(10); // shared_ptr<int> outOfPlaceSharedPtr(value, &nda); //.. // Next we create an in-place representation of a shared 'int' object that is // also initialized to 10: //.. // shared_ptr<int> inPlaceSharedPtr; // inPlaceSharedPtr.createInplace(&nda, 10); //.. // The memory layouts of these two representations are shown below (where // 'd_ptr_p' refers to the shared object and 'd_rep_p' refers to the // representation): //.. // Out-of-Place Representation In-Place Representation // ---------------------------- ---------------------------- // // +------------+ +------------+ // | | | | // | d_ptr_p ------>+-----------+ | d_ptr_p ---------+ // | | | 10 | | | | // | | +-----------+ | | | // | | | | | // | d_rep_p ------>+-----------+ | d_rep_p ------>+-v---------+ // | | | reference | | | |+---------+| // | | | counts | | | || 10 || // +------------+ +-----------+ +------------+ |+---------+| // | reference | // | counts | // +-----------+ //.. // An out-of-place representation is generally less efficient than an in-place // representation since it usually requires at least two allocations (one to // construct the object and one to construct the shared pointer representation // for the object). // // Creating an in-place shared pointer does not require the template parameter // type to inherit from a special class (such as // 'bsl::enable_shared_from_this'); in that case, 'shared_ptr' supports up to // fourteen arguments that can be passed directly to the object's constructor. // For in-place representations, both the object and the representation can be // constructed in one allocation as opposed to two, effectively creating an // "intrusive" reference counter. Note that the size of the allocation is // determined at compile-time from the combined footprint of the object and of // the reference counts. It is also possible to create shared pointers to // buffers whose sizes are determined at runtime, although such buffers consist // of raw (uninitialized) memory. // ///Weak Pointers using "in-place" or Pooled Shared Pointer Representations ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // A weak pointer that is not in the empty state shares a common representation // (used to refer to the shared object) with the shared (or other weak) pointer // from which it was constructed, and holds this representation until it is // either destroyed or reset. This common representation is not destroyed and // deallocated (although the shared object itself may have been destroyed) // until all weak references to that common representation have been released. // // Due to this behavior the *memory* *footprint* of shared objects that are // constructed "in-place" in the shared pointer representation (see above) is // not deallocated until all weak references to that shared object are // released. Note that a shared object is always destroyed when the last // shared reference to it is released. Also note that the same behavior // applies if the shared object were obtained from a class that pools shared // pointer representations (for example, 'bcec_SharedObjectPool'). // // For example suppose we have a class with a large memory footprint: //.. // class ClassWithLargeFootprint { // // This class has a large memory footprint. // // // TYPES // enum { BUFFER_SIZE = 1024 }; // // The size of the buffer owned by this 'class'. // // // DATA // char d_buffer[BUFFER_SIZE]; // // // ... // }; //.. // We then create an "in-place" shared pointer to an object of // 'ClassWithLargeFootprint' using the 'createInplace' method of 'shared_ptr'. // The 'sp' shared pointer representation of 'sp' will create a // 'ClassWithLargeFootprint' object "in-place": //.. // shared_ptr<ClassWithLargeFootprint> sp; // sp.createInplace(); //.. // Next we construct a weak pointer from this (in-place) shared pointer: //.. // weak_ptr<ClassWithLargeFootprint> wp(sp); //.. // Now releasing all shared references to the shared object (using the 'reset' // function) causes the object's destructor to be called, but the // representation is not destroyed (and the object's footprint is not // deallocated) until 'wp' releases its weak reference: //.. // sp.reset(); // The object's footprint is not deallocated until all weak // // references to it are released. // // wp.reset(); // The release of the *last* weak reference results in the // // destruction and deallocation of the representation and the // // object's footprint. //.. // If a shared object has a large footprint, and the client anticipates there // will be weak references to it, then an out-of-place shared pointer // representation may be preferred because it destroys the shared object and // deallocates its footprint when the last *shared* reference is released, // regardless of whether there are any outstanding weak references to the same // representation. // ///Correct Usage of the Allocator Model ///------------------------------------ // Note that once constructed, there is no difference in type, usage, or // efficiency between in-place and out-of-place shared pointers, except that an // in-place shared pointer will exhibit greater locality of reference and // faster destruction (because there is only one allocated block). Also note // that an object created with an allocator needs to have this allocator // specified as its last constructor argument, but this allocator may be // different from the one passed as the first argument to 'createInplace'. // // For example, consider the following snippet of code: //.. // bslma::Allocator *allocator1, *allocator2; // // ... // shared_ptr<bsl::string> ptr; // ptr.createInplace(allocator1, bsl::string("my string"), allocator2); //.. // Here 'allocator1' is used to obtain the shared pointer representation and // the in-place 'bsl::string' object, and 'allocator2' is used by the // 'bsl::string' object (having the value "my string") for its memory // allocations. Typically, both allocators will be the same, and so the same // allocator will need to be specified twice. // ///Deleters ///-------- // When the last shared reference to a shared object is released, the object is // destroyed using the "deleter" provided when the associated shared pointer // representation was created. 'shared_ptr' supports two kinds of "deleter" // objects, which vary in how they are invoked. A "function-like" deleter is // any language entity that can be invoked such that the expression // 'deleterInstance(objectPtr)' is a valid expression. A "factory" deleter is // any language entity that can be invoked such that the expression // 'deleterInstance.deleteObject(objectPtr)' is a valid expression, where // 'deleterInstance' is an instance of the "deleter" object, and 'objectPtr' is // a pointer to the shared object. Factory deleters are a BDE extension to the // ISO C++ Standard Library specification for 'shared_ptr'. In summary: //.. // Deleter Expression used to destroy 'objectPtr' // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "function-like" deleterInstance(objectPtr); // "factory" deleterInstance.deleteObject(objectPtr); //.. // The following are examples of function-like deleters that delete an object // of 'my_Type': //.. // void deleteObject(my_Type *object); // // Delete the specified 'object'. // // void releaseObject(my_Type *object); // // Release the specified 'object'. // // struct FunctionLikeDeleterObject { // // This 'struct' provides an 'operator()' that can be used to delete a // // 'my_Type' object. // // void operator()(my_Type *object); // // Destroy the specified 'object'. // }; //.. // The following, on the other hand is an example of a factory deleter: //.. // class my_Factory { // // // . . . // // // MANIPULATORS // my_Type *createObject(bslma::Allocator *basicAllocator = 0); // // Create a 'my_Type' object. Optionally specify a // // 'basicAllocator' used to supply memory. If 'basicAllocator' is // // 0, the currently installed default allocator is used. // // void deleteObject(my_Type *object); // // Delete the specified 'object'. // }; // // class my_Allocator : public bslma::Allocator { /* ... */ }; //.. // Note that 'deleteObject' is provided by all 'bslma' allocators and by any // object that implements the 'bdlma::Deleter' protocol. Thus, any of these // objects can be used as a factory deleter. The purpose of this design is to // allow 'bslma' allocators and factories to be used seamlessly as deleters. // // The selection of which expression is used by 'shared_ptr' to destroy a // shared object is based on how the deleter is passed to the shared pointer // object: Deleters that are passed by *address* are assumed to be factory // deleters (unless they are function pointers), while those that are passed by // *value* are assumed to be function-like. Note that if the wrong interface // is used for a deleter, i.e., if a function-like deleter is passed by // pointer, or a factory deleter is passed by value, and the expression used to // delete the object is invalid, a compiler diagnostic will be emitted // indicating the error. // // In general, deleters should have defined behavior when called with a null // pointer. In all cases, throwing an exception out of a copy constructor for // a deleter will yield undefined behavior. // // The following are examples of constructing shared pointers with the // addresses of factory deleters: //.. // my_Factory factory; // my_Type *myPtr1 = factory.createObject(); // shared_ptr<my_Type> mySharedPtr1(myPtr1, &factory, 0); // // bdema_SequentialAllocator sa; // my_Type *myPtr2 = new (sa) my_Type(&sa); // shared_ptr<my_Type> mySharedPtr2(myPtr2, &sa); //.. // Note that the deleters are passed *by address* in the above examples. // // The following are examples of constructing shared pointers with // function-like deleters: //.. // my_Type *getObject(bslma::Allocator *basicAllocator = 0); // // my_Type *myPtr3 = getObject(); // shared_ptr<my_Type> mySharedPtr3(myPtr3, &deleteObject); // // my_Type *myPtr4 = getObject(); // FunctionLikeDeleterObject deleter; // shared_ptr<my_Type> mySharedPtr4(myPtr4, deleter, &sa); //.. // Note that 'deleteObject' is also passed by address, but 'deleter' is passed // by value in the above examples. Function-like deleter objects (passed by // value) are stored by value in the representation and therefore *must* be // copy-constructible. Note that even though the deleter may be passed by // reference, it is a copy (owned by the shared pointer representation) that is // invoked and thus the 'deleterInstance' is not required, nor assumed, to be // non-modifiable. (For the example above, note that 'operator()' is // intentionally *not* defined 'const'.) // ///Aliasing ///-------- // 'shared_ptr' supports a powerful "aliasing" feature. That is, a shared // pointer can be constructed to refer to a shared object of a certain type // while the shared pointer representation it holds refers to a shared object // of any (possibly different) type. All references are applied to the // "aliased" shared object referred to by the representation and is used for // reference counting. This "aliased" shared object is passed to the deleter // upon destruction of the last instance of that shared pointer. Consider the // following snippet of code: //.. // class Event { /* ... */ }; // void getEvents(bsl::list<Event> *list); // // void enqueueEvents(bcec_Queue<shared_ptr<Event> > *queue) // { // bsl::list<Event> eventList; // getEvents(&eventList); // for (bsl::list<Event>::iterator it = eventList.begin(); // it != eventList.end(); // ++it) { // shared_ptr<Event> e; // e.createInplace(0, *it); // Copy construct the event into a new // // shared ptr. // queue->pushBack(e); // } // } //.. // In the above example, 'getEvents' loads into the provided 'bsl::list' a // sequence of event objects. The 'enqueueEvents' function constructs an empty // list and calls 'getEvents' to fill the list with 'Event' objects. Once the // event list is filled, each event item is pushed as a shared pointer // (presumably because events are "expensive" to construct and may be // referenced simultaneously from multiple threads) onto the provided queue. // Since the individual event items are contained by value within the list, // pointers to them cannot be passed if it cannot be guaranteed that they will // not live beyond the lifetime of the list itself. Therefore, an expensive // copy operation is required to create individually-managed instances of each // of the list items. The 'createInplace' operation is used to reduce the // number of required allocations, but this might still be too expensive. Now // consider the following alternate implementation of 'enqueueEvents' using the // 'shared_ptr' aliasing feature: //.. // void enqueueEvents(bcec_Queue<shared_ptr<Event> > *queue) // { // shared_ptr<bsl::list<Event> > eventList; // eventList.createInplace(0); // Construct a shared pointer // // to the event list containing // // all of the events. // getEvents(eventList.get()); // // for (bsl::list<Event>::iterator it = eventList->begin(); // it != eventList->end(); // ++it) { // // Push each event onto the queue as an alias of the 'eventList' // // shared pointer. When all the alias references have been // // released, the event list will be destroyed deleting all the // // events at once. // // queue->pushBack(shared_ptr<Event>(eventList, &*it)); // } // } //.. // In the implementation above, we create a single shared pointer to the // 'Event' list, 'eventList', and use that to create 'Event' shared pointers // that are aliased to 'eventList'. The lifetime of each 'Event' object is // then tied to the 'eventList' and it will not be destroyed until the // 'eventList' is destroyed. // ///Type Casting ///------------ // A 'shared_ptr' object of a given type can be implicitly or explicitly cast // to a 'shared_ptr' of another type. // ///Implicit Casting /// - - - - - - - - // As with native pointers, a shared pointer to a derived type can be directly // assigned to a shared pointer to a base type. In other words, if the // following statements are valid: //.. // class A { virtual void foo(); }; // polymorphic type // class B : public A {}; // B *bp = 0; // A *ap = bp; //.. // then the following statements: //.. // shared_ptr<B> spb; // shared_ptr<A> spa; // spa = spb; //.. // and: //.. // shared_ptr<B> spb; // shared_ptr<A> spa(spb); //.. // are also valid. Note that in all of the above cases, the destructor of 'B' // will be invoked when the object is destroyed even if 'A' does not provide a // virtual destructor. // ///Explicit Casting /// - - - - - - - - // Through "aliasing", a shared pointer of any type can be explicitly cast to a // shared pointer of any other type using any legal cast expression. For // example, to statically cast a shared pointer to type 'A' ('shared_ptr<A>') // to a shared pointer to type 'B' ('shared_ptr<B>'), one can simply do the // following: //.. // shared_ptr<A> spa; // shared_ptr<B> spb(spa, static_cast<B *>(spa.get())); //.. // or even the less safe C-style cast: //.. // shared_ptr<A> spa; // shared_ptr<B> spb(spa, (B *)(spa.get())); //.. // For convenience, several utility functions are provided to perform common // C++ casts. Dynamic casts, static casts, and 'const' casts are all provided. // Explicit casting is supported through the 'bslstl::SharedPtrUtil' utility. // The following example demonstrates the dynamic casting of a shared pointer // to type 'A' ('shared_ptr<A>') to a shared pointer to type 'B' // ('shared_ptr<B>'): //.. // bslma::NewDeleteAllocator nda; // shared_ptr<A> sp1(new (nda) A(), &nda); // shared_ptr<B> sp2 = bslstl::SharedPtrUtil::dynamicCast<B>(sp1); // shared_ptr<B> sp3; // bslstl::SharedPtrUtil::dynamicCast(&sp3, sp1); // shared_ptr<B> sp4; // sp4 = bslstl::SharedPtrUtil::dynamicCast<B>(sp1); //.. // To test if the cast succeeded, simply test if the target shared pointer // refers to a non-null value (assuming the source was not null, of course): //.. // if (sp2) { // // The cast succeeded. // } else { // // The cast failed. // } //.. // As previously stated, the shared object will be destroyed correctly // regardless of how it is cast. // ///Converting to and from 'BloombergLP::bslma::ManagedPtr' ///------------------------------------------------------- // A 'shared_ptr' can be converted to a 'BloombergLP::bslma::ManagedPtr' while // still retaining proper reference counting. When a shared pointer is // converted to a 'BloombergLP::bslma::ManagedPtr', the number of references to // the shared object is incremented. When the managed pointer is destroyed (if // not transferred to another managed pointer first), the number of references // will be decremented. If the number of references reaches zero, then the // shared object will be destroyed. The 'managedPtr' function can be used to // create a managed pointer from a shared pointer. // // A 'shared_ptr' also can be constructed from a // 'BloombergLP::bslma::ManagedPtr'. The resulting shared pointer takes over // the management of the object and will use the deleter from the original // 'BloombergLP::bslma::ManagedPtr' to destroy the managed object when all the // references to that shared object are released. // ///Weak Pointers using "in-place" or Pooled Shared Pointer Representations ///----------------------------------------------------------------------- // A weak pointer that is not in the empty state shares a common representation // (used to refer to the shared object) with the shared (or other weak) pointer // from which it was constructed, and holds this representation until it is // either destroyed or reset. This common representation is not destroyed and // deallocated (although the shared object itself may have been destroyed) // until all weak references to that common representation have been released. // // Due to this behavior the memory footprint of shared objects that are // constructed "in-place" in the shared pointer representation (refer to the // component-level documentation of 'bsl::shared_ptr' for more information on // shared pointers with "in-place" representations) is not deallocated until // all weak references to that shared object are released. Note that a shared // object is always destroyed when the last shared reference to it is released. // Also note that the same behavior is applicable if the shared objects were // obtained from a class that pools shared pointer representations (for // example, 'bcec_SharedObjectPool'). // // For example suppose we have a class with a large memory footprint: //.. // class ClassWithLargeFootprint { // // This class has a large memory footprint. // // // TYPES // enum { BUFFER_SIZE = 1024 }; // // The size of the buffer owned by this 'class'. // // // DATA // char d_buffer[BUFFER_SIZE]; // // // ... // }; //.. // We then create an "in-place" shared pointer to an object of // 'ClassWithLargeFootprint' using the 'createInplace' method of // 'bsl::shared_ptr'. The 'sp' shared pointer representation of 'sp' will // create a 'ClassWithLargeFootprint' object "in-place": //.. // bsl::shared_ptr<ClassWithLargeFootprint> sp; // sp.createInplace(); //.. // Next we construct a weak pointer from this (in-place) shared pointer: //.. // bsl::weak_ptr<ClassWithLargeFootprint> wp(sp); //.. // Now releasing all shared references to the shared object (using the 'reset' // function) causes the object's destructor to be called, but the // representation is not destroyed (and the object's footprint is not // deallocated) until 'wp' releases its weak reference: //.. // sp.reset(); // The object's footprint is not deallocated until all weak // // references to it are released. // // wp.reset(); // The release of the *last* weak reference results in the // // destruction and deallocation of the representation and the // // object's footprint. //.. // If a shared object has a large footprint, and the client anticipates there // will be weak references to it, then it may be advisable to create an // out-of-place shared pointer representation, which destroys the shared object // and deallocates its footprint when the last *shared* reference to it is // released, regardless of whether there are any outstanding weak references to // the same representation. // ///C++ Standard Compliance ///----------------------- // This component provides an (extended) standard-compliant implementation of // 'std::shared_ptr' and 'std::weak_ptr' (section 20.7.2, [util.smartptr], of // the ISO C++11 standard)). However, it does not support the atomic shared // pointer interface, nor provide the C++17 interface for 'shared_ptr' of an // array type. When using a C++03 compiler, its interface is limited to the // set of operations that can be implemented by an implementation of the C++03 // language, e,g., there are no exception specifications, nor 'constexpr' // constructors, and move operations are emulated with 'bslmf::MovableRef'. // // In addition to the standard interface, this component supports allocators // following the 'bslma::Allocator' protocol in addition to the C++ Standard // Allocators (section 17.6.3.5, [allocator.requirements]), supports "factory" // style deleters in addition to function-like deleters, and interoperation // with 'bslma::ManagedPtr' smart pointers. // ///Usage ///----- // The following examples demonstrate various features and uses of shared // pointers. // ///Example 1: Basic Usage /// - - - - - - - - - - - // The following example demonstrates the creation of a shared pointer. First, // we declare the type of object that we wish to manage: //.. // class MyUser { // // DATA // bsl::string d_name; // int d_id; // // public: // // CREATORS // MyUser(bslma::Allocator *alloc = 0) : d_name(alloc), d_id(0) {} // MyUser(const bsl::string& name, int id, bslma::Allocator *alloc = 0) // : d_name(name, alloc) // , d_id(id) // { // } // MyUser(const MyUser& original, bslma::Allocator *alloc = 0) // : d_name(original.d_name, alloc) // , d_id(original.d_id) // { // } // // // MANIPULATORS // void setName(const bsl::string& name) { d_name = name; } // void setId(int id) { d_id = id; } // // // ACCESSORS // const bsl::string& name() const { return d_name; } // int id() const { return d_id; } // }; //.. // The 'createUser' utility function (below) creates a 'MyUser' object using // the provided allocator and returns a shared pointer to the newly-created // object. Note that the shared pointer's internal representation will also be // allocated using the same allocator. Also note that if 'allocator' is 0, the // currently-installed default allocator is used. //.. // shared_ptr<MyUser> createUser(bsl::string name, // int id, // bslma::Allocator *allocator = 0) // { // allocator = bslma::Default::allocator(allocator); // MyUser *user = new (*allocator) MyUser(name, id, allocator); // return shared_ptr<MyUser>(user, allocator); // } //.. // Since the 'createUser' function both allocates the object and creates the // shared pointer, it can benefit from the in-place facilities to avoid an // extra allocation. Again, note that the representation will also be // allocated using the same allocator (see the section "Correct Usage of the // Allocator Model" above). Also note that if 'allocator' is 0, the // currently-installed default allocator is used. //.. // shared_ptr<MyUser> createUser2(bsl::string name, // int id, // bslma::Allocator *allocator = 0) // { // shared_ptr<MyUser> user; // user.createInplace(allocator, name, id, allocator); // return user; // } //.. // Note that the shared pointer allocates both the reference count and the // 'MyUser' object in a single region of memory (which is the memory that will // eventually be deallocated), but refers to the 'MyUser' object only. // ///Using Custom Deleters ///- - - - - - - - - - - // The following examples demonstrate the use of custom deleters with shared // pointers. // ///Example 2: Nil Deleters /// - - - - - - - - // There are cases when an interface calls for an object to be passed as a // shared pointer, but the object being passed is not owned by the caller // (e.g., a pointer to a static variable). In these cases, it is possible to // create a shared pointer specifying 'bslstl::SharedPtrNilDeleter' as the // deleter. The deleter function provided by 'bslstl::SharedPtrNilDeleter' is // a no-op and does not delete the object. The following example demonstrates // the use of 'shared_ptr' using a 'bslstl::SharedPtrNilDeleter'. The code // uses the 'MyUser' class defined in Example 1. In this example, an // asynchronous transaction manager is implemented. Transactions are enqueued // into the transaction manager to be processed at some later time. The user // associated with the transaction is passed as a shared pointer. Transactions // can originate from the "system" or from "users". // // We first declare the transaction manager and transaction info classes: //.. // class MyTransactionInfo { // // Transaction Info... // }; // // class MyTransactionManager { // // // PRIVATE MANIPULATORS // int enqueueTransaction(shared_ptr<MyUser> user, // const MyTransactionInfo& transaction); // public: // // CLASS METHODS // static MyUser *systemUser(bslma::Allocator *basicAllocator = 0); // // // MANIPULATORS // int enqueueSystemTransaction(const MyTransactionInfo& transaction); // // int enqueueUserTransaction(const MyTransactionInfo& transaction, // shared_ptr<MyUser> user); // // }; //.. // The 'systemUser' class method returns the same 'MyUser' object and should // not be destroyed by its users: //.. // MyUser *MyTransactionManager::systemUser( // bslma::Allocator * /* basicAllocator */) // { // static MyUser *systemUserSingleton; // if (!systemUserSingleton) { // // instantiate singleton in a thread-safe manner passing // // 'basicAllocator' // // // . . . // } // return systemUserSingleton; // } //.. // For enqueuing user transactions, simply proxy the information to // 'enqueueTransaction'. //.. // inline // int MyTransactionManager::enqueueUserTransaction( // const MyTransactionInfo& transaction, // shared_ptr<MyUser> user) // { // return enqueueTransaction(user, transaction); // } //.. // For system transactions, we must use the 'MyUser' objected returned from the // 'systemUser' 'static' method. Since we do not own the returned object, we // cannot directly construct a 'shared_ptr' object for it: doing so would // result in the singleton being destroyed when the last reference to the // shared pointer is released. To solve this problem, we construct a // 'shared_ptr' object for the system user using a nil deleter. When the last // reference to the shared pointer is released, although the deleter will be // invoked to destroy the object, it will do nothing. //.. // int MyTransactionManager::enqueueSystemTransaction( // const MyTransactionInfo& transaction) // { // shared_ptr<MyUser> user(systemUser(), // bslstl::SharedPtrNilDeleter(), // 0); // return enqueueTransaction(user, transaction); // } //.. // ///Example 3: Basic Weak Pointer Usage ///- - - - - - - - - - - - - - - - - - // This example illustrates the basic syntax needed to create and use a // 'bsl::weak_ptr'. Suppose that we want to construct a weak pointer that // refers to an 'int' managed by a shared pointer. Next we define the shared // pointer and assign a value to the shared 'int': //.. // bsl::shared_ptr<int> intPtr; // intPtr.createInplace(bslma::Default::allocator()); // *intPtr = 10; // assert(10 == *intPtr); //.. // Next we construct a weak pointer to the 'int': //.. // bsl::weak_ptr<int> intWeakPtr(intPtr); // assert(!intWeakPtr.expired()); //.. // 'bsl::weak_ptr' does not provide direct access to the shared object being // referenced. To access and manipulate the 'int' from the weak pointer, we // have to obtain a shared pointer from it: //.. // bsl::shared_ptr<int> intPtr2 = intWeakPtr.lock(); // assert(intPtr2); // assert(10 == *intPtr2); // // *intPtr2 = 20; // assert(20 == *intPtr); // assert(20 == *intPtr2); //.. // We remove the weak reference to the shared 'int' by calling the 'reset' // method: //.. // intWeakPtr.reset(); // assert(intWeakPtr.expired()); //.. // Note that resetting the weak pointer does not affect the shared pointers // referencing the 'int' object: //.. // assert(20 == *intPtr); // assert(20 == *intPtr2); //.. // Now, we construct another weak pointer referencing the shared 'int': //.. // bsl::weak_ptr<int> intWeakPtr2(intPtr); // assert(!intWeakPtr2.expired()); //.. // Finally 'reset' all shared references to the 'int', which will cause the // weak pointer to become "expired"; any subsequent attempt to obtain a shared // pointer from the weak pointer will return a shared pointer in the default // constructed (empty) state: //.. // intPtr.reset(); // intPtr2.reset(); // assert(intWeakPtr2.expired()); // assert(!intWeakPtr2.lock()); //.. // ///Example 4: Breaking Cyclical Dependencies ///- - - - - - - - - - - - - - - - - - - - - // Weak pointers are frequently used to break cyclical dependencies between // objects that store references to each other via a shared pointer. Consider // for example a simplified news alert system that sends news alerts to users // based on keywords that they register for. The user information is stored in // the 'User' class and the details of the news alert are stored in the 'Alert' // class. The class definitions for 'User' and 'Alert' are provided below // (with any code not relevant to this example elided): //.. // class Alert; // // class User { // // This class stores the user information required for listening to // // alerts. // // bsl::vector<bsl::shared_ptr<Alert> > d_alerts; // alerts user is // // registered for // // // ... // // public: // // MANIPULATORS // void addAlert(const bsl::shared_ptr<Alert>& alertPtr) // { // // Add the specified 'alertPtr' to the list of alerts being // // monitored by this user. // // d_alerts.push_back(alertPtr); // } // // // ... // }; //.. // Now we define an alert class, 'Alert': //.. // class Alert { // // This class stores the alert information required for sending // // alerts. // // bsl::vector<bsl::shared_ptr<User> > d_users; // users registered // // for this alert // // public: // // MANIPULATORS // void addUser(const bsl::shared_ptr<User>& userPtr) // { // // Add the specified 'userPtr' to the list of users monitoring this // // alert. // // d_users.push_back(userPtr); // } // // // ... // }; // //.. // Even though we have released 'alertPtr' and 'userPtr' there still exists a // cyclic reference between the two objects, so none of the objects are // destroyed. // // We can break this cyclical dependency we define a modified alert class // 'ModifiedAlert' that stores a weak pointer to a 'ModifiedUser' object. // Below is the definition for the 'ModifiedUser' class that is identical to // the 'User' class, the only difference being that it stores shared pointer to // 'ModifiedAlert's instead of 'Alert's: //.. // class ModifiedAlert; // // class ModifiedUser { // // This class stores the user information required for listening to // // alerts. // // bsl::vector<bsl::shared_ptr<ModifiedAlert> > d_alerts;// alerts user is // // registered for // // // ... // // public: // // MANIPULATORS // void addAlert(const bsl::shared_ptr<ModifiedAlert>& alertPtr) // { // // Add the specified 'alertPtr' to the list of alerts being // // monitored by this user. // // d_alerts.push_back(alertPtr); // } // // // ... // }; //.. // Now we define the 'ModifiedAlert' class: //.. // class ModifiedAlert { // // This class stores the alert information required for sending // // alerts. // //.. // Note that the user is stored by a weak pointer instead of by a shared // pointer: //.. // bsl::vector<bsl::weak_ptr<ModifiedUser> > d_users; // users registered // // for this alert // // public: // // MANIPULATORS // void addUser(const bsl::weak_ptr<ModifiedUser>& userPtr) // { // // Add the specified 'userPtr' to the list of users monitoring this // // alert. // // d_users.push_back(userPtr); // } // // // ... // }; //.. // ///Example 5: Caching /// - - - - - - - - - // Suppose we want to implement a peer to peer file sharing system that allows // users to search for files that match specific keywords. A simplistic // version of such a system with code not relevant to the usage example elided // would have the following parts: // // a) A peer manager class that maintains a list of all connected peers and // updates the list based on incoming peer requests and disconnecting peers. // The following would be a simple interface for the Peer and PeerManager // classes: //.. // class Peer { // // This class stores all the relevant information for a peer. // // // ... // }; // // class PeerManager { // // This class acts as a manager of peers and adds and removes peers // // based on peer requests and disconnections. // // // DATA //.. // The peer objects are stored by shared pointer to allow peers to be passed to // search results and still allow their asynchronous destruction when peers // disconnect. //.. // bsl::map<int, bsl::shared_ptr<Peer> > d_peers; // // // ... // }; //.. // b) A peer cache class that stores a subset of the peers that are used for // sending search requests. The cache may select peers based on their // connection bandwidth, relevancy of previous search results, etc. For // brevity the population and flushing of this cache is not shown: //.. // class PeerCache { // // This class caches a subset of all peers that match certain criteria // // including connection bandwidth, relevancy of previous search // // results, etc. // //.. // Note that the cached peers are stored as a weak pointer so as not to // interfere with the cleanup of Peer objects by the PeerManager if a Peer goes // down. //.. // // DATA // bsl::list<bsl::weak_ptr<Peer> > d_cachedPeers; // // public: // // TYPES // typedef bsl::list<bsl::weak_ptr<Peer> >::const_iterator PeerConstIter; // // // ... // // // ACCESSORS // PeerConstIter begin() const { return d_cachedPeers.begin(); } // PeerConstIter end() const { return d_cachedPeers.end(); } // }; //.. // c) A search result class that stores a search result and encapsulates a peer // with the file name stored by the peer that best matches the specified // keywords: //.. // class SearchResult { // // This class provides a search result and encapsulates a particular // // peer and filename combination that matches a specified set of // // keywords. // //.. // The peer is stored as a weak pointer because when the user decides to select // a particular file to download from this peer, the peer might have // disconnected. //.. // // DATA // bsl::weak_ptr<Peer> d_peer; // bsl::string d_filename; // // public: // // CREATORS // SearchResult(const bsl::weak_ptr<Peer>& peer, // const bsl::string& filename) // : d_peer(peer) // , d_filename(filename) // { // } // // // ... // // // ACCESSORS // const bsl::weak_ptr<Peer>& peer() const { return d_peer; } // const bsl::string& filename() const { return d_filename; } // }; //.. // d) A search function that takes a list of keywords and returns available // results by searching the cached peers: //.. // void search(bsl::vector<SearchResult> * /* results */, // const PeerCache& peerCache, // const bsl::vector<bsl::string>& /* keywords */) // { // for (PeerCache::PeerConstIter iter = peerCache.begin(); // iter != peerCache.end(); // ++iter) { //.. // First we check if the peer is still connected by acquiring a shared pointer // to the peer. If the acquire operation succeeds, then we can send the peer a // request to send back the file best matching the specified keywords: //.. // bsl::shared_ptr<Peer> peerSharedPtr = iter->lock(); // if (peerSharedPtr) { // // // Search the peer for file best matching the specified // // keywords and if a file is found add the returned // // SearchResult object to result. // // // ... // } // } // } //.. // e) A download function that downloads a file selected by the user: //.. // void download(const SearchResult& result) // { // bsl::shared_ptr<Peer> peerSharedPtr = result.peer().lock(); // if (peerSharedPtr) { // // Download the result.filename() file from peer knowing that // // the peer is still connected. // } // } //.. // ///Example 6: Custom Deleters /// - - - - - - - - - // The role of a "deleter" is to allow users to define a custom "cleanup" for a // shared object. Although cleanup generally involves destroying the object, // this need not be the case. The following example demonstrates the use of a // custom deleter to construct "locked" pointers. First we declare a custom // deleter that, when invoked, releases the specified mutex and signals the // specified condition variable. //.. // class my_MutexUnlockAndBroadcastDeleter { // // // DATA // bcemt_Mutex *d_mutex_p; // mutex to lock (held, not owned) // bcemt_Condition *d_cond_p; // condition variable used to broadcast // // (held, not owned) // // public: // // CREATORS // my_MutexUnlockAndBroadcastDeleter(bcemt_Mutex *mutex, // bcemt_Condition *cond) // // Create this 'my_MutexUnlockAndBroadcastDeleter' object. Use // // the specified 'cond' to broadcast a signal and the specified // // 'mutex' to serialize access to 'cond'. The behavior is // // undefined unless 'mutex' is not 0 and 'cond' is not 0. // : d_mutex_p(mutex) // , d_cond_p(cond) // { // BSLS_ASSERT(mutex); // BSLS_ASSERT(cond); // // d_mutex_p->lock(); // } // // my_MutexUnlockAndBroadcastDeleter( // my_MutexUnlockAndBroadcastDeleter& original) // : d_mutex_p(original.d_mutex_p) // , d_cond_p(original.d_cond_p) // { // } //.. // Since this deleter does not actually delete anything, 'void *' is used in // the signature of 'operator()', allowing it to be used with any type of // object. //.. // void operator()(void *) // { // d_cond_p->broadcast(); // d_mutex_p->unlock(); // } // }; //.. // Next we declare a thread-safe queue 'class'. The 'class' uses a // non-thread-safe 'bsl::deque' to implement the queue. Thread-safe 'push' and // 'pop' operations that push and pop individual items are provided. For // callers that wish to gain direct access to the queue, the 'queue' method // returns a shared pointer to the queue using the // 'my_MutexUnlockAndBroadcastDeleter'. Callers can safely access the queue // through the returned shared pointer. Once the last reference to the pointer // is released, the mutex will be unlocked and the condition variable will be // signaled to allow waiting threads to re-evaluate the state of the queue. //.. // template <class ELEMENT_TYPE> // class my_SafeQueue { // // // DATA // bcemt_Mutex d_mutex; // bcemt_Condition d_cond; // bsl::deque<ELEMENT_TYPE> d_queue; // // // . . . // // public: // // MANIPULATORS // void push(const ELEMENT_TYPE& obj); // // ELEMENT_TYPE pop(); // // shared_ptr<bsl::deque<ELEMENT_TYPE> > queue(); // }; // // template <class ELEMENT_TYPE> // void my_SafeQueue<ELEMENT_TYPE>::push(const ELEMENT_TYPE& obj) // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); // d_queue.push_back(obj); // d_cond.signal(); // } // // template <class ELEMENT_TYPE> // ELEMENT_TYPE my_SafeQueue<ELEMENT_TYPE>::pop() // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); // while (!d_queue.size()) { // d_cond.wait(&d_mutex); // } // ELEMENT_TYPE value(d_queue.front()); // d_queue.pop_front(); // return value; // } // // template <class ELEMENT_TYPE> // shared_ptr<bsl::deque<ELEMENT_TYPE> > // my_SafeQueue<ELEMENT_TYPE>::queue() // { // return shared_ptr<bsl::deque<ELEMENT_TYPE> >( // &d_queue, // MyMutexUnlockAndBroadcastDeleter(&d_mutex, &d_cond), // 0); // } //.. // ///Implementation Hiding ///- - - - - - - - - - - // 'shared_ptr' refers to the template parameter type on which it is // instantiated "in name only". This allows for the instantiation of shared // pointers to incomplete or 'void' types. This feature is useful for // constructing interfaces where returning a pointer to a shared object is // desirable, but in order to control access to the object its interface cannot // be exposed. The following examples demonstrate two techniques for achieving // this goal using a 'shared_ptr'. // ///Example 7: Hidden Interfaces /// - - - - - - - - - - - - - - // Example 7 demonstrates the use of incomplete types to hide the interface of // a 'my_Session' type. We begin by declaring the 'my_SessionManager' 'class', // which allocates and manages 'my_Session' objects. The interface ('.h') // merely forward declares 'my_Session'. The actual definition of the // interface is in the implementation ('.cpp') file. // // We forward-declare 'my_Session' to be used (in name only) in the definition // of 'my_SessionManager': //.. // class my_Session; //.. // Next, we define the 'my_SessionManager' class: //.. // class my_SessionManager { // // // TYPES // typedef bsl::map<int, shared_ptr<my_Session> > HandleMap; // // // DATA // bcemt_Mutex d_mutex; // HandleMap d_handles; // int d_nextSessionId; // bslma::Allocator *d_allocator_p; // //.. // It is useful to have a designated name for the 'shared_ptr' to 'my_Session': //.. // public: // // TYPES // typedef shared_ptr<my_Session> my_Handle; //.. // We need only a default constructor: //.. // // CREATORS // my_SessionManager(bslma::Allocator *allocator = 0); //.. // The 3 methods that follow construct a new session object and return a // 'shared_ptr' to it. Callers can transfer the pointer, but they cannot // directly access the object's methods since they do not have access to its // interface. //.. // // MANIPULATORS // my_Handle openSession(const bsl::string& sessionName); // void closeSession(my_Handle handle); // // // ACCESSORS // bsl::string getSessionName(my_Handle handle) const; // }; //.. // Now, in the implementation of the code, we can define and implement the // 'my_Session' class: //.. // class my_Session { // // // DATA // bsl::string d_sessionName; // int d_handleId; // // public: // // CREATORS // my_Session(const bsl::string& sessionName, // int handleId, // bslma::Allocator *basicAllocator = 0); // // // ACCESSORS // int handleId() const; // const bsl::string& sessionName() const; // }; // // // CREATORS // inline // my_Session::my_Session(const bsl::string& sessionName, // int handleId, // bslma::Allocator *basicAllocator) // : d_sessionName(sessionName, basicAllocator) // , d_handleId(handleId) // { // } // // // ACCESSORS // inline // int my_Session::handleId() const // { // return d_handleId; // } // // inline // const bsl::string& my_Session::sessionName() const // { // return d_sessionName; // } //.. // The following shows the implementation of 'my_SessionManager'. Note that // the interface for 'my_Session' is not known: //.. // inline // my_SessionManager::my_SessionManager(bslma::Allocator *allocator) // : d_nextSessionId(1) // , d_allocator_p(bslma::Default::allocator(allocator)) // { // } // // inline // my_SessionManager::my_Handle // my_SessionManager::openSession(const bsl::string& sessionName) // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); // my_Handle session(new (*d_allocator_p) my_Session(sessionName, // d_nextSessionId++, // d_allocator_p)); // d_handles[session->handleId()] = session; // return session; // } // // inline // void my_SessionManager::closeSession(my_Handle handle) // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); // HandleMap::iterator it = d_handles.find(handle->handleId()); // if (it != d_handles.end()) { // d_handles.erase(it); // } // } // // inline // bsl::string my_SessionManager::getSessionName(my_Handle handle) const // { // return handle->sessionName(); // } //.. // ///Example 8: Opaque Types /// - - - - - - - - // In the above example, users could infer that 'my_Handle' is a pointer to a // 'my_Session' but have no way to directly access it's methods since the // interface is not exposed. In the following example, 'my_SessionManager' is // re-implemented to provide an even more opaque session handle. In this // implementation, 'my_Handle' is redefined using 'void' providing no // indication of its implementation. Note that using 'void' will require // casting in the implementation and, therefore, will be a little more // expensive. // // In the interface, define 'my_SessionManager' as follows: //.. // class my_SessionManager { // // // TYPES // typedef bsl::map<int, shared_ptr<void> > HandleMap; // // // DATA // bcemt_Mutex d_mutex; // HandleMap d_handles; // int d_nextSessionId; // bslma::Allocator *d_allocator_p; //.. // It is useful to have a name for the 'void' 'shared_ptr' handle. //.. // public: // // TYPES // typedef shared_ptr<void> my_Handle; // // // CREATORS // my_SessionManager(bslma::Allocator *allocator = 0); // // // MANIPULATORS // my_Handle openSession(const bsl::string& sessionName); // void closeSession(my_Handle handle); // // // ACCESSORS // bsl::string getSessionName(my_Handle handle) const; // }; //.. // Next we define the methods of 'my_SessionManager': //.. // // CREATORS // inline // my_SessionManager::my_SessionManager(bslma::Allocator *allocator) // : d_nextSessionId(1) // , d_allocator_p(bslma::Default::allocator(allocator)) // { // } // // // MANIPULATORS // inline // my_SessionManager::my_Handle // my_SessionManager::openSession(const bsl::string& sessionName) // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); //.. // Notice that 'my_Handle', which is a shared pointer to 'void', can be // transparently assigned to a shared pointer to a 'my_Session' object. This // is because the 'shared_ptr' interface allows shared pointers to types that // can be cast to one another to be assigned directly. //.. // my_Handle session(new (*d_allocator_p) my_Session(sessionName, // d_nextSessionId++, // d_allocator_p)); // shared_ptr<my_Session> myhandle = // bslstl::SharedPtrUtil::staticCast<my_Session>(session); // d_handles[myhandle->handleId()] = session; // return session; // } // // inline // void my_SessionManager::closeSession(my_Handle handle) // { // bcemt_LockGuard<bcemt_Mutex> lock(&d_mutex); //.. // Perform a static cast from 'shared_ptr<void>' to 'shared_ptr<my_Session>'. //.. // shared_ptr<my_Session> myhandle = // bslstl::SharedPtrUtil::staticCast<my_Session>(handle); //.. // Test to make sure that the pointer is non-null before using 'myhandle': //.. // if (!myhandle.get()) { // return; // RETURN // } // // HandleMap::iterator it = d_handles.find(myhandle->handleId()); // if (it != d_handles.end()) { // d_handles.erase(it); // } // } // // bsl::string my_SessionManager::getSessionName(my_Handle handle) const // { // shared_ptr<my_Session> myhandle = // bslstl::SharedPtrUtil::staticCast<my_Session>(handle); // // if (!myhandle.get()) { // return bsl::string(); // } else { // return myhandle->sessionName(); // } // } //.. #include <bslscm_version.h> #include <bslstl_hash.h> #include <bslstl_pair.h> #include <bslstl_referencewrapper.h> #include <bslstl_sharedptrallocateinplacerep.h> #include <bslstl_sharedptrallocateoutofplacerep.h> #include <bslma_allocator.h> #include <bslma_allocatortraits.h> #include <bslma_default.h> #include <bslma_managedptr.h> #include <bslma_sharedptrinplacerep.h> #include <bslma_sharedptroutofplacerep.h> #include <bslma_sharedptrrep.h> #include <bslma_stdallocator.h> #include <bslmf_addlvaluereference.h> #include <bslmf_addpointer.h> #include <bslmf_conditional.h> #include <bslmf_enableif.h> #include <bslmf_haspointersemantics.h> #include <bslmf_integralconstant.h> #include <bslmf_isarray.h> #include <bslmf_isbitwisemoveable.h> #include <bslmf_isconvertible.h> #include <bslmf_isfunction.h> #include <bslmf_ispointer.h> #include <bslmf_movableref.h> #include <bslmf_nestedtraitdeclaration.h> #include <bslmf_util.h> #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_deprecatefeature.h> #include <bsls_keyword.h> #include <bsls_libraryfeatures.h> #include <bsls_nullptr.h> #include <bsls_platform.h> #include <bsls_unspecifiedbool.h> #include <bsls_util.h> // 'forward<T>(V)' #include <functional> // use 'std::less' to order pointers #include <memory> // 'std::auto_ptr', 'std::unique_ptr' #include <ostream> // 'std::basic_ostream' #include <stddef.h> // 'size_t', 'ptrdiff_t' #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bsls_nativestd.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // Include version that can be compiled with C++03 // Generated on Wed Oct 26 08:50:25 2022 // Command line: sim_cpp11_features.pl bslstl_sharedptr.h # define COMPILING_BSLSTL_SHAREDPTR_H # include <bslstl_sharedptr_cpp03.h> # undef COMPILING_BSLSTL_SHAREDPTR_H #else #if defined(BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC) // Here and throughout the file wherever 'auto_ptr' is used, suspend // GCC reporting of deprecated declarations since the use of 'auto_ptr' // in this standard interface is required. # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULT_TEMPLATE_ARGS) \ && (!defined(BSLS_PLATFORM_CMP_MSVC) || BSLS_PLATFORM_CMP_VERSION >= 1900) # define BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS 1 #if BSLS_PLATFORM_CMP_VERSION >= 1910 && \ BSLS_PLATFORM_CMP_VERSION < 1920 && \ BSLS_COMPILERFEATURES_CPLUSPLUS >= 201703L // Visual Studio 2017 in C++17 mode crashes with an internal compiler error on // the shared pointer SFINAE code. See {DRQS 148281696}. # undef BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS #endif // If the macro 'BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS' is defined, then a // conforming C++11 compiler will define the constructors in this component in // such a way that they will not be selected during overload resolution unless // they would instantiate correctly. This means that code depending on the // result of 'is_constructible' and similar traits will have the expected // behavior. There is no attempt to support this feature in C++03. // // Support for SFINAE-queries on the constructability of a 'shared_ptr' depend // on a variety of C++11 language features, including "expression-SFINAE". // However, the main language feature that enables SFINAE elimination of a // constructor is the ability to use default template arguments in a function // template. It is significantly preferred to use the template parameter list, // rather than add additional default arguments to the constructor signatures, // as there are so many constructor overloads in this component that there is a // real risk of introducing ambiguities that would need to be worked around. // Therefore, the 'BSLS_COMPILERFEATURES_SUPPORT_DEFAULT_TEMPLATE_ARGS' macro // serves as our proxy for whether SFINAE-constructors are enabled in this // component. Note that the MSVC 2015 compiler almost supported // "expression-SFINAE", to the extent that it works for this component, unlike // earlier versions of that compiler. We therefore make a special version-test // on Microsoft in addition to the feature testing. #endif # if defined(BSLS_PLATFORM_CMP_GNU) # define BSLSTL_SHAREDPTR_NO_PARTIAL_ORDER_ON_ALLOCATOR_POINTER 1 // If the macro 'BSLSTL_SHAREDPTR_NO_PARTIAL_ORDER_ON_ALLOCATOR_POINTER' is // defined, we recognize that some compilers need an extra hint to disambiguate // overload resolution when passed a 'bslma::Allocator *' pointer, that might // also deduce (incorrectly) as a C++11-style allocator. Gcc is known to have // this problem, and was tested as recently as gcc 9. This compiler has a // problem partially ordering function templates that differ only by the first // argument deducing as any object type ('T'), or deducing as the a pointer to // something ('T*'). The rules for partial ordering should make the second // overload a stronger match when passed a pointer; however, this compiler // complains about ambiguities when additional parameters are involved. This // appears to be fixed in gcc 10. #endif #if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) // Note the intentional comma in the first line of the definition of each // macro, which allows these macros to be applied incrementally, even when the // alternate definition is empty. This avoids the problem of introducing new // template parameters along with the macros in the non-SFINAE-supporting case // below. # define BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsPointerConvertible< \ CONVERTIBLE_TYPE, \ ELEMENT_TYPE>::value>::type * \ = nullptr # define BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsPointerConvertible< \ CONVERTIBLE_TYPE, \ ELEMENT_TYPE>::value>::type * # define BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsPointerCompatible< \ COMPATIBLE_TYPE, \ ELEMENT_TYPE>::value>::type * \ = nullptr # define BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsPointerCompatible< \ COMPATIBLE_TYPE, \ ELEMENT_TYPE>::value>::type * # define BSLSTL_SHAREDPTR_DECLARE_IF_DELETER(FUNCTOR, ARGUMENT) , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsCallable <FUNCTOR, \ ARGUMENT *>::k_VALUE || \ BloombergLP::bslstl::SharedPtr_IsFactoryFor<FUNCTOR, \ ARGUMENT>::k_VALUE>::type * \ = nullptr # define BSLSTL_SHAREDPTR_DEFINE_IF_DELETER(FUNCTOR, ARGUMENT) , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsCallable <FUNCTOR, \ ARGUMENT *>::k_VALUE || \ BloombergLP::bslstl::SharedPtr_IsFactoryFor<FUNCTOR, \ ARGUMENT >::k_VALUE>::type * # define BSLSTL_SHAREDPTR_DECLARE_IF_NULLPTR_DELETER(FUNCTOR) , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsCallable <FUNCTOR, \ nullptr_t>::k_VALUE || \ BloombergLP::bslstl::SharedPtr_IsNullableFactory< \ FUNCTOR>::k_VALUE>::type * = nullptr # define BSLSTL_SHAREDPTR_DEFINE_IF_NULLPTR_DELETER(FUNCTOR) , \ typename enable_if< \ BloombergLP::bslstl::SharedPtr_IsCallable <FUNCTOR, \ nullptr_t>::k_VALUE || \ BloombergLP::bslstl::SharedPtr_IsNullableFactory< \ FUNCTOR>::k_VALUE>::type * #else // Do not attempt to support SFINAE in constructors in a C++03 compiler # define BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE # define BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE # define BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE # define BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE # define BSLSTL_SHAREDPTR_DECLARE_IF_DELETER(FUNCTOR, ARGUMENT) # define BSLSTL_SHAREDPTR_DEFINE_IF_DELETER(FUNCTOR, ARGUMENT) # define BSLSTL_SHAREDPTR_DECLARE_IF_NULLPTR_DELETER(FUNCTOR) # define BSLSTL_SHAREDPTR_DEFINE_IF_NULLPTR_DELETER(FUNCTOR) #endif // BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS // Some SFINAE checks, when enabled, make use of discarded-value expressions // (as the left-hand side of a comma operator). Clang compilers based on // versions of LLVM earlier than 12 contain a bug in which substitution // failures are not caught in discarded-value expressions when used in SFINAE // contexts (this includes Clang 11 and earlier, and Apple Clang 13 and // earlier). In order to ensure that these compilers catch substitution // failures in such expressions, this component does not discard them. Note // that this is dangerous, because not discarding the expression allows the // possibility that the comma operator will be overloaded on the type of the // expression, and so it is preferable to discard the expression where // possible. #if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) # if !defined(BSLS_PLATFORM_CMP_CLANG) \ || !defined(__APPLE_CC__) && BSLS_PLATFORM_CMP_VERSION >= 120000 \ || defined(__APPLE_CC__) && BSLS_PLATFORM_CMP_VERSION > 130000 # define BSLSTL_SHAREDPTR_SFINAE_DISCARD(EXPRESSION) \ static_cast<void>(EXPRESSION) # else # define BSLSTL_SHAREDPTR_SFINAE_DISCARD(EXPRESSION) \ (EXPRESSION) # endif #endif namespace BloombergLP { namespace bslstl { struct SharedPtr_RepFromExistingSharedPtr { // This 'struct' is for internal use only, providing a tag for 'shared_ptr' // constructors to recognize that a passed 'SharedPtrRep' was obtained from // an existing 'shared_ptr' object. }; struct SharedPtr_ImpUtil; // Forward declaration of 'SharedPtr_ImpUtil'. This is needed because this // struct is a friend of 'enable_shared_from_this' in the 'bsl' namespace. #if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) template <class FUNCTOR, class ARG> struct SharedPtr_IsCallable; // Forward declaration of component-private type trait to indicate whether // an object of (template parameter) type 'FUNCTOR' can be called as a // function with an argument of (template parameter) type 'ARG' template <class FACTORY, class ARG> struct SharedPtr_IsFactoryFor; // Forward declaration of component-private type trait to indicate whether // a pointer to a 'FACTORY' has a 'deleteObject' member that can be called // as 'factory->deleteObject((ARG *)p)'. template <class FACTORY> struct SharedPtr_IsNullableFactory; // Forward declaration of component-private type trait to indicate whether // a pointer to a 'FACTORY' has a 'deleteObject' member that can be called // as 'factory->deleteObject((ARG *)p)'. template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerConvertible; // Forward declaration of component-private type trait to indicate whether // a pointer to a 'SOURCE_TYPE' can be converted to a pointer to a // 'DEST_TYPE'. [util.smartptr.shared.const]/8 says "either DEST_TYPE is // U[N] and SOURCE_TYPE(*)[N] is convertible to DEST_TYPE*, or DEST_TYPE is // U[] and SOURCE_TYPE(*)[] is convertible to DEST_TYPE*". template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerCompatible; // Forward declaration of component-private type trait to indicate whether // a pointer to a 'SOURCE_TYPE' is compatible with a pointer to // 'DEST_TYPE'. [util.smartptr.shared]/5 says: "for the purposes of ..., // a pointer type SOURCE_TYPE* is said to be compatible with a pointer type // DEST_TYPE* when either SOURCE_TYPE* is convertible to DEST_TYPE* or // SOURCE_TYPE is U[N] and DEST_TYPE is cv U[]." #endif } // close package namespace } // close enterprise namespace namespace bsl { template<class ELEMENT_TYPE> class enable_shared_from_this; template <class ELEMENT_TYPE> class shared_ptr; template <class ELEMENT_TYPE> class weak_ptr; // ================ // class shared_ptr // ================ template <class ELEMENT_TYPE> class shared_ptr { // This class provides a thread-safe reference-counted "smart pointer" to // support "shared ownership" of objects: a shared pointer ensures that the // shared object is destroyed, using the appropriate deletion method, only // when there are no shared references to it. The object (of template // parameter type 'ELEMENT_TYPE') referred to by a shared pointer may be // accessed directly using the '->' operator, or the dereference operator // (operator '*') can be used to obtain a reference to that object. // // Note that the object referred to by a shared pointer representation is // usually the same as the object referred to by that shared pointer (of // the same 'ELEMENT_TYPE'), but this need not always be true in the // presence of conversions or "aliasing": the object referred to (of // template parameter type 'ELEMENT_TYPE') by the shared pointer may differ // from the object of type 'COMPATIBLE_TYPE' (see the "Aliasing" section in // the component-level documentation) referred to by the shared pointer // representation. // // More generally, this class supports a complete set of *in*-*core* // pointer semantic operations. public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(shared_ptr<ELEMENT_TYPE>, bsl::is_nothrow_move_constructible); // TYPES typedef typename bsl::remove_extent<ELEMENT_TYPE>::type element_type; // For shared pointers to non-array types, 'element_type' is an alias // to the 'ELEMENT_TYPE' template parameter. Otherwise, it is an alias // to the type contained in the array. typedef weak_ptr<ELEMENT_TYPE> weak_type; // 'weak_type' is an alias to a weak pointer with the same element type // as this 'shared_ptr'. private: // DATA element_type *d_ptr_p; // pointer to the shared object BloombergLP::bslma::SharedPtrRep *d_rep_p; // pointer to the representation // object that manages the // shared object // PRIVATE TYPES typedef shared_ptr<ELEMENT_TYPE> SelfType; // 'SelfType' is an alias to this 'class', for compilers that do not // recognize plain 'shared_ptr'. typedef typename BloombergLP::bsls::UnspecifiedBool<shared_ptr>::BoolType BoolType; // FRIENDS template <class COMPATIBLE_TYPE> friend class shared_ptr; friend struct BloombergLP::bslstl::SharedPtr_ImpUtil; private: // PRIVATE CLASS METHODS template <class INPLACE_REP> static BloombergLP::bslma::SharedPtrRep *makeInternalRep( ELEMENT_TYPE *, INPLACE_REP *, BloombergLP::bslma::SharedPtrRep *rep); // Return the specified 'rep'. template <class COMPATIBLE_TYPE, class ALLOCATOR> static BloombergLP::bslma::SharedPtrRep *makeInternalRep( COMPATIBLE_TYPE *ptr, ALLOCATOR *, BloombergLP::bslma::Allocator *allocator); // Return the address of a new out-of-place representation for a shared // pointer that manages the specified 'ptr' and uses the specified // 'allocator' to destroy the object pointed to by 'ptr'. Use // 'allocator' to supply memory. template <class COMPATIBLE_TYPE, class DELETER> static BloombergLP::bslma::SharedPtrRep *makeInternalRep( COMPATIBLE_TYPE *ptr, DELETER *deleter, ...); // Return the address of a new out-of-place representation for a shared // pointer that manages the specified 'ptr' and uses the specified // 'deleter' to destroy the object pointed to by 'ptr'. Use the // currently installed default allocator to supply memory. public: // CREATORS BSLS_KEYWORD_CONSTEXPR shared_ptr() BSLS_KEYWORD_NOEXCEPT; // Create an empty shared pointer, i.e., a shared pointer with no // representation that does not refer to any object and has no // deleter. BSLS_KEYWORD_CONSTEXPR shared_ptr(bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT; // IMPLICIT // Create an empty shared pointer, i.e., a shared pointer with no // representation that does not refer to any object and has no // deleter. template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE> explicit shared_ptr(CONVERTIBLE_TYPE *ptr); // Create a shared pointer that manages a modifiable object of // (template parameter) type 'CONVERTIBLE_TYPE' and refers to the // specified '(ELEMENT_TYPE *)ptr'. The currently installed default // allocator is used to allocate and deallocate the internal // representation of the shared pointer. When all references have been // released, the object pointed to by the managed pointer will be // destroyed by a call to 'delete ptr'. If 'CONVERTIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. If 'ptr' is 0, // then this shared pointer will still allocate an internal // representation to share ownership of that empty state, which will be // reclaimed when the last reference is destroyed. If an exception is // thrown allocating storage for the representation, then 'delete ptr' // will be called. Note that if 'ptr' is a null-pointer constant, the // compiler will actually select the 'shared_ptr(bsl::nullptr_t)' // constructor, resulting in an empty shared pointer. template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE> shared_ptr(CONVERTIBLE_TYPE *ptr, BloombergLP::bslma::Allocator *basicAllocator); // Create a shared pointer that manages a modifiable object of // (template parameter) type 'CONVERTIBLE_TYPE' and refers to the // specified 'ptr' cast to a pointer to the (template parameter) type // 'ELEMENT_TYPE'. If the specified 'basicAllocator' is not 0, then // 'basicAllocator' is used to allocate and deallocate the internal // representation of the shared pointer and to destroy the shared // object when all references have been released; otherwise, the // currently installed default allocator is used. If // 'CONVERTIBLE_TYPE *' is not implicitly convertible to // 'ELEMENT_TYPE *', then a compiler diagnostic will be emitted // indicating the error. If 'ptr' is 0, then this shared pointer will // still allocate an internal representation to share ownership of that // empty state, which will be reclaimed when the last reference is // destroyed. Note that if 'ptr' is a null-pointer constant, the // compiler will actually select the // 'shared_ptr(bsl::nullptr_t, BloombergLP::bslma::Allocator *)' // constructor, resulting in an empty shared pointer. Note that if // 'basicAllocator' is a pointer to a class derived from // 'bslma::Allocator', the compiler will actually select the following // (more general) constructor that has the same behavior: //.. // template <class CONVERTIBLE_TYPE, class DELETER> // shared_ptr(CONVERTIBLE_TYPE *ptr, DELETER * deleter); //.. shared_ptr(ELEMENT_TYPE *ptr, BloombergLP::bslma::SharedPtrRep *rep); // Create a shared pointer that takes ownership of the specified 'rep' // and refers to the modifiable object at the specified 'ptr' address. // The number of references to 'rep' is *NOT* incremented. Note that // if 'rep' is a pointer to a class derived from // 'BloombergLP::bslma::SharedPtrRep', the compiler will actually // select the following (more general) constructor that has the same // behavior: //.. // template <class COMPATIBLE_TYPE, class DELETER> // shared_ptr(COMPATIBLE_TYPE *ptr, DELETER * deleter); //.. shared_ptr(ELEMENT_TYPE *ptr, BloombergLP::bslma::SharedPtrRep *rep, BloombergLP::bslstl::SharedPtr_RepFromExistingSharedPtr); // Create a shared pointer that takes ownership of the specified 'rep' // and refers to the modifiable object at the specified 'ptr' address. // The number of references to 'rep' is *NOT* incremented. The // behavior is undefined unless 'rep' was previously obtained from an // existing 'shared_ptr', 'rep->disposeObject' has not been called, and // 'rep->numReferences() > 0'. Note that this constructor is intended // for use by 'weak_ptr::lock', and it would be surprising to find // another client. This solves an obscure problem that arises from // unusual use of classes derived from 'enable_shared_from_this'. // Further note that the caller is responsible for incrementing the // 'numReferences' count prior to calling this constructor, in order to // maintain a consistent reference count when this 'shared_ptr' object // releases the shared object from its management. template <class CONVERTIBLE_TYPE, class DELETER BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DECLARE_IF_DELETER(DELETER *, CONVERTIBLE_TYPE)> shared_ptr(CONVERTIBLE_TYPE *ptr, DELETER *deleter); // Create a shared pointer that manages a modifiable object of // (template parameter) type 'CONVERTIBLE_TYPE', refers to the // specified 'ptr' cast to a pointer to the (template parameter) type // 'ELEMENT_TYPE', and uses the specified 'deleter' to delete the // shared object when all references have been released. Use the // currently installed default allocator to allocate and deallocate the // internal representation of the shared pointer, unless 'DELETER' is a // class derived from either 'bslma::Allocator' or // 'bslma::SharedPtrRep'; if 'DELETER' is a class derived from // 'bslma::allocator', create a shared pointer as if calling the // constructor: //.. // template <class CONVERTIBLE_TYPE> // shared_ptr(CONVERTIBLE_TYPE *ptr, // BloombergLP::bslma::Allocator *basicAllocator); //.. // If 'DELETER' is a class derived from 'bslma::SharedPtrRep', create a // shared pointer as if calling the constructor: //.. // shared_ptr(ELEMENT_TYPE *ptr, // BloombergLP::bslma::SharedPtrRep *rep); //.. // If 'DELETER' does not derive from either 'bslma::Allocator' or // 'BloombergLP::bslma::SharedPtrRep', then 'deleter' shall be a // pointer to a factory object that exposes a member function that can // be invoked as 'deleteObject(ptr)' that will be called to destroy the // object at the 'ptr' address (i.e., 'deleter->deleteObject(ptr)' will // be called to delete the shared object). (See the "Deleters" section // in the component-level documentation.) If 'CONVERTIBLE_TYPE *' is // not implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. If 'ptr' is 0, // then the null pointer will be reference counted, and the deleter // will be called when the last reference is destroyed. If an // exception is thrown when allocating storage for the internal // representation, then 'deleter(ptr)' will be called. Note that this // method is a BDE extension and not part of the C++ standard // interface. template <class CONVERTIBLE_TYPE, class DELETER BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DECLARE_IF_DELETER(DELETER, CONVERTIBLE_TYPE)> shared_ptr(CONVERTIBLE_TYPE *ptr, DELETER deleter, BloombergLP::bslma::Allocator *basicAllocator = 0); // Create a shared pointer that manages a modifiable object of // (template parameter) type 'CONVERTIBLE_TYPE', refers to the // specified '(ELEMENT_TYPE *)ptr', and uses the specified 'deleter' to // delete the shared object when all references have been released. // Optionally specify a 'basicAllocator' to allocate and deallocate the // internal representation of the shared pointer (including a copy of // 'deleter'). If 'basicAllocator' is 0, the currently installed // default allocator is used. 'DELETER' shall be either a function // pointer or a "factory" deleter that may be invoked to destroy the // object referred to by a single argument of type 'CONVERTIBLE_TYPE *' // (i.e., 'deleter(ptr)' or 'deleter->deleteObject(ptr)' will be called // to destroy the shared object). (See the "Deleters" section in the // component-level documentation.) If 'CONVERTIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then this constructor // will not be selected by overload resolution. If 'ptr' is 0, then // the null pointer will be reference counted, and 'deleter(ptr)' will // be called when the last reference is destroyed. If an exception is // thrown when allocating storage for the internal representation, then // 'deleter(ptr)' will be called. The behavior is undefined unless the // constructor making a copy of 'deleter' does not throw an exception. template <class CONVERTIBLE_TYPE, class DELETER, class ALLOCATOR BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DECLARE_IF_DELETER(DELETER, CONVERTIBLE_TYPE)> shared_ptr(CONVERTIBLE_TYPE *ptr, DELETER deleter, ALLOCATOR basicAllocator, typename ALLOCATOR::value_type * = 0); // Create a shared pointer that manages a modifiable object of // (template parameter) type 'CONVERTIBLE_TYPE', refers to the // specified 'ptr' cast to a pointer to the (template parameter) type // 'ELEMENT_TYPE', and uses the specified 'deleter' to delete the // shared object when all references have been released. Use the // specified 'basicAllocator' to allocate and deallocate the internal // representation of the shared pointer (including a copy of the // 'deleter'). The (template parameter) type 'DELETER' shall be either // a function pointer or a function-like deleter that may be invoked to // destroy the object referred to by a single argument of type // 'CONVERTIBLE_TYPE *' (i.e., 'deleter(ptr)' will be called to destroy // the shared object). (See the "Deleters" section in the component- // level documentation.) The (template parameter) type 'ALLOCATOR' // shall satisfy the Allocator requirements of the C++ standard (C++11 // 17.6.3.5, [allocator.requirements]). If 'CONVERTIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. If 'ptr' is 0, // then the null pointer will be reference counted, and 'deleter(ptr)' // will be called when the last reference is destroyed. If an // exception is thrown when allocating storage for the internal // representation, then 'deleter(ptr)' will be called. The behavior is // undefined unless the constructor making a copy of 'deleter' does not // throw an exception. Note that the final dummy parameter is a simple // SFINAE check that the (template parameter) 'ALLOCATOR' type probably // satisfies the standard allocator requirements; in particular, it // will not match pointer types, so any pointers to 'bslma::Allocator' // derived classes will dispatch to the constructor above this, and not // be greedily matched to a generic type parameter. shared_ptr(nullptr_t nullPointerLiteral, BloombergLP::bslma::Allocator *basicAllocator); // Create an empty shared pointer. The specified 'nullPointerLiteral' // and 'basicAllocator' are not used. Note that use of this // constructor is equivalent to calling the default constructor. template <class DELETER BSLSTL_SHAREDPTR_DECLARE_IF_NULLPTR_DELETER(DELETER)> shared_ptr(nullptr_t nullPointerLiteral, DELETER deleter, BloombergLP::bslma::Allocator *basicAllocator = 0); // Create a shared pointer that reference-counts the null pointer, and // calls the specified 'deleter' with a null pointer (i.e., invokes // 'deleter((ELEMENT_TYPE *)0)') when the last shared reference is // destroyed. The specified 'nullPointerLiteral' is not used. // Optionally specify a 'basicAllocator' to allocate and deallocate the // internal representation of the shared pointer (including a copy of // 'deleter'). If 'basicAllocator' is 0, the currently installed // default allocator is used. If an exception is thrown when // allocating storage for the internal representation, then // 'deleter((ELEMENT_TYPE *)0)' will be called. The behavior is // undefined unless 'deleter' can be called with a null pointer, and // unless the constructor making a copy of 'deleter' does not throw an // exception. template <class DELETER, class ALLOCATOR BSLSTL_SHAREDPTR_DECLARE_IF_NULLPTR_DELETER(DELETER)> shared_ptr(nullptr_t nullPointerLiteral, DELETER deleter, ALLOCATOR basicAllocator, typename ALLOCATOR::value_type * = 0); // Create a shared pointer that reference-counts the null pointer, // calls the specified 'deleter' with a null pointer (i.e., invokes // 'deleter((ELEMENT_TYPE *)0)') when the last shared reference is // destroyed, and uses the specified 'basicAllocator' to allocate and // deallocate the internal representation of the shared pointer // (including a copy of the 'deleter'). The (template parameter) type // 'DELETER' shall be either a function pointer or a function-like // deleter (See the "Deleters" section in the component- level // documentation). The (template parameter) type 'ALLOCATOR' shall // satisfy the Allocator requirements of the C++ standard (C++11 // 17.6.3.5, [allocator.requirements]). The specified // 'nullPointerLiteral' is not used. If an exception is thrown when // allocating storage for the internal representation, then // 'deleter((ELEMENT_TYPE *)0)' will be called. The behavior is // undefined unless 'deleter' can be called with a null pointer, and // unless the constructor making a copy of 'deleter' does not throw an // exception. Note that the final dummy parameter is a simple SFINAE // check that the 'ALLOCATOR' type probably satisfies the standard // allocator requirements; in particular, it will not match pointer // types, so any pointers to 'bslma::Allocator' derived classes will // dispatch to the constructor above this, and not be greedily matched // to a generic type parameter. template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE> shared_ptr( BloombergLP::bslma::ManagedPtr<CONVERTIBLE_TYPE> managedPtr, BloombergLP::bslma::Allocator *basicAllocator = 0); // IMPLICIT // Create a shared pointer that takes over the management of the // modifiable object (if any) previously managed by the specified // 'managedPtr' to the (template parameter) type 'CONVERTIBLE_TYPE', // and that refers to '(ELEMENT_TYPE *)managedPtr.ptr()'. The deleter // used in the 'managedPtr' will be used to destroy the shared object // when all references have been released. Optionally specify a // 'basicAllocator' used to allocate and deallocate the internal // representation of the shared pointer. If 'basicAllocator' is 0, the // currently installed default allocator is used. If // 'CONVERTIBLE_TYPE *' is not implicitly convertible to // 'ELEMENT_TYPE *', then a compiler diagnostic will be emitted // indicating the error. Note that if 'managedPtr' is empty, then an // empty shared pointer is created and 'basicAllocator' is ignored. // Also note that if 'managedPtr' owns a reference to another shared // object (due to a previous call to 'shared_ptr<T>::managedPtr') then // no memory will be allocated, and this 'shared_ptr' will adopt the // 'ManagedPtr's ownership of that shared object. #if defined(BSLS_LIBRARYFEATURES_HAS_CPP98_AUTO_PTR) template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE> explicit shared_ptr(std::auto_ptr<CONVERTIBLE_TYPE>& autoPtr, BloombergLP::bslma::Allocator *basicAllocator = 0); // Create a shared pointer that takes over the management of the // modifiable object previously managed by the specified 'autoPtr' to // the (template parameter) type 'CONVERTIBLE_TYPE', and that refers to // '(ELEMENT_TYPE *)autoPtr.get()'. 'delete(autoPtr.release())' will // be called to destroy the shared object when all references have been // released. Optionally specify a 'basicAllocator' used to allocate // and deallocate the internal representation of the shared pointer. // If 'basicAllocator' is 0, the currently installed default allocator // is used. If 'CONVERTIBLE_TYPE *' is not implicitly convertible to // 'ELEMENT_TYPE *', then a compiler diagnostic will be emitted // indicating the error. explicit shared_ptr(std::auto_ptr_ref<ELEMENT_TYPE> autoRef, BloombergLP::bslma::Allocator *basicAllocator = 0); // Create a shared pointer that takes over the management of the // modifiable object of (template parameter) type 'COMPATIBLE_TYPE' // previously managed by the auto pointer object that the specified // 'autoRef' refers to; this shared pointer refers to the same object // that it manages, and 'delete(get())' will be called to destroy the // shared object when all references have been released. Optionally // specify a 'basicAllocator' used to allocate and deallocate the // internal representation of the shared pointer. If 'basicAllocator' // is 0, the currently installed default allocator is used. This // function does not exist unless 'COMPATIBLE_TYPE *' is convertible to // 'ELEMENT_TYPE *'. #endif #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_UNIQUE_PTR) # if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) template <class COMPATIBLE_TYPE, class UNIQUE_DELETER, typename enable_if<is_convertible< typename std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>::pointer, ELEMENT_TYPE *>::value>::type * = nullptr> shared_ptr(std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>&& adoptee, BloombergLP::bslma::Allocator *basicAllocator = 0); // IMPLICIT // Create a shared pointer that takes over the management of the // modifiable object previously managed by the specified 'adoptee' to // the (template parameter) type 'COMPATIBLE_TYPE', and that refers to // '(ELEMENT_TYPE *)autoPtr.get()'. 'delete(autoPtr.release())' will // be called to destroy the shared object when all references have been // released. Optionally specify a 'basicAllocator' used to allocate // and deallocate the internal representation of the shared pointer. // If 'basicAllocator' is 0, the currently installed default allocator // is used. This function does not exist unless // 'unique_ptr<COMPATIBLE_TYPE, DELETER>::pointer' is convertible to // 'ELEMENT_TYPE *'. Note that this function creates a 'shared_ptr' // with an unspecified deleter type that has satisfies this contract, // which might not be the deleter of 'rhs', which is specified by the // C++ standard. # else template <class COMPATIBLE_TYPE, class UNIQUE_DELETER> shared_ptr(std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>&& adoptee, BloombergLP::bslma::Allocator *basicAllocator = 0, typename enable_if<is_convertible< typename std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>::pointer, ELEMENT_TYPE *>::value, BloombergLP::bslstl::SharedPtr_ImpUtil>::type = BloombergLP::bslstl::SharedPtr_ImpUtil()) // IMPLICIT // Create a shared pointer that takes over the management of the // modifiable object previously managed by the specified 'adoptee' to // the (template parameter) type 'COMPATIBLE_TYPE', and that refers to // '(ELEMENT_TYPE *)autoPtr.get()'. 'delete(autoPtr.release())' will // be called to destroy the shared object when all references have been // released. Optionally specify a 'basicAllocator' used to allocate // and deallocate the internal representation of the shared pointer. // If 'basicAllocator' is 0, the currently installed default allocator // is used. This function does not exist unless // 'unique_ptr<COMPATIBLE_TYPE, DELETER>::pointer' is convertible to // 'ELEMENT_TYPE *'. Note that this function creates a 'shared_ptr' // with an unspecified deleter type that has satisfies this contract, // which might not be the deleter of 'rhs', which is specified by the // C++ standard. : d_ptr_p(adoptee.get()) , d_rep_p(0) { // This constructor template must be defined inline inside the class // definition, as Microsoft Visual C++ does not recognize the // definition as matching this signature when placed out-of-line. typedef BloombergLP::bslma::SharedPtrInplaceRep< std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER> > Rep; if (d_ptr_p) { basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator, BloombergLP::bslmf::MovableRefUtil::move(adoptee)); d_rep_p = rep; BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis( d_ptr_p, this); } } # endif // BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS #endif // BSLS_LIBRARYFEATURES_HAS_CPP11_UNIQUE_PTR template <class ANY_TYPE> shared_ptr(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *object) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that manages the same modifiable object (if // any) as the specified 'source' shared pointer to the (template // parameter) type 'ANY_TYPE', and that refers to the modifiable object // at the specified 'object' address. The resulting shared pointer is // known as an "alias" of 'source'. Note that typically the objects // referred to by 'source' and 'object' have identical lifetimes (e.g., // one might be a part of the other), so that the deleter for 'source' // will destroy them both, but they do not necessarily have the same // type. Also note that if 'source' is empty, then an empty shared // pointer is created, even if 'object' is not null (in which case this // empty shared pointer will refer to the same object as 'object'). // Also note that if 'object' is null and 'source' is not empty, then a // reference-counted null pointer alias will be created. template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> shared_ptr(const shared_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that manages the same modifiable object (if // any) as the specified 'other' shared pointer to the (template // parameter) type 'COMPATIBLE_TYPE', uses the same deleter as 'other' // to destroy the shared object, and refers to // '(ELEMENT_TYPE*)other.get()'. If 'COMPATIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. Note that if // 'other' is empty, then an empty shared pointer is created, which may // still point to an un-managed object if 'other' were constructed // through an aliasing constructor. shared_ptr(const shared_ptr& original) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that refers to and manages the same object // (if any) as the specified 'original' shared pointer, and uses the // same deleter as 'original' to destroy the shared object. Note that // if 'original' is empty, then an empty shared pointer is created, // which may still point to an un-managed object if 'original' were // constructed through an aliasing constructor. shared_ptr(BloombergLP::bslmf::MovableRef<shared_ptr> original) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that refers to and assumes management of the // same object (if any) as the specified 'original' shared pointer, // using the same deleter as 'original' to destroy the shared object, // and reset 'original' to an empty state, not pointing to any object. // Note that if 'original' is empty, then an empty shared pointer is // created, which may still point to an un-managed object if 'original' // were constructed through an aliasing constructor. #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> shared_ptr(shared_ptr<COMPATIBLE_TYPE>&& other) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that refers to and assumes management of the // same object (if any) as the specified 'other' shared pointer to the // (template parameter) type 'COMPATIBLE_TYPE', using the same deleter // as 'other' to destroy the shared object, and refers to // '(ELEMENT_TYPE*)other.get()'. If 'COMPATIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. Note that if // 'other' is empty, then an empty shared pointer is created, which may // still point to an un-managed object if 'other' were constructed // through an aliasing constructor. #else template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> shared_ptr( BloombergLP::bslmf::MovableRef<shared_ptr<COMPATIBLE_TYPE> > other) BSLS_KEYWORD_NOEXCEPT; // Create a shared pointer that refers to and assumes management of the // same object (if any) as the specified 'other' shared pointer to the // (template parameter) type 'COMPATIBLE_TYPE', using the same deleter // as 'other' to destroy the shared object, and refers to // '(ELEMENT_TYPE*)other.get()'. If 'COMPATIBLE_TYPE *' is not // implicitly convertible to 'ELEMENT_TYPE *', then a compiler // diagnostic will be emitted indicating the error. Note that if // 'other' is empty, then an empty shared pointer is created, which may // still point to an un-managed object if 'other' were constructed // through an aliasing constructor. #endif template<class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> explicit shared_ptr(const weak_ptr<COMPATIBLE_TYPE>& ptr); // Create a shared pointer that refers to and manages the same object // as the specified 'ptr' if 'ptr.expired()' is 'false'; otherwise, // create a shared pointer in the empty state. Note that the // referenced and managed objects may be different if 'ptr' was created // from a 'shared_ptr' in an aliasing state. #if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template<class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> explicit shared_ptr( BloombergLP::bslmf::MovableRef<weak_ptr<COMPATIBLE_TYPE> > ptr); // Create a shared pointer that refers to and manages the same object // as the specified 'ptr' if 'ptr.expired()' is 'false'; otherwise, // create a shared pointer in the empty state. Note that the // referenced and managed objects may be different if 'ptr' was created // from a 'shared_ptr' in an aliasing state. Also note that this // overloaded constructor is necessary only for C++03 compilers that // rely on the BDE move-emulation type, 'bslmf::MovableRef'; a C++11 // compiler will pass rvalues directly to the constructor taking a // 'const weak_ptr&', rendering this constructor redundant. #endif ~shared_ptr(); // Destroy this shared pointer. If this shared pointer refers to a // (possibly shared) object, then release the reference to that object, // and destroy the shared object using its associated deleter if this // shared pointer is the last reference to that object. // MANIPULATORS shared_ptr& operator=(const shared_ptr& rhs) BSLS_KEYWORD_NOEXCEPT; // Make this shared pointer manage the same modifiable object as the // specified 'rhs' shared pointer to the (template parameter) type // 'COMPATIBLE_TYPE', use the same deleter as 'rhs', and refer to // '(ELEMENT_TYPE *)rhs.get()'; return a reference providing modifiable // access to this shared pointer. Note that if 'rhs' is empty, then // this shared pointer will also be empty after the assignment. Also // note that if '*this' is the same object as 'rhs', then this method // has no effect. shared_ptr& operator=(BloombergLP::bslmf::MovableRef<shared_ptr> rhs) BSLS_KEYWORD_NOEXCEPT; // Make this shared pointer manage the same modifiable object as the // specified 'rhs' shared pointer to the (template parameter) type // 'COMPATIBLE_TYPE', use the same deleter as 'rhs', and refer to // 'rhs.get()'; return a reference providing modifiable access to this // shared pointer. Reset 'rhs' to an empty state, not pointing to any // object, unless '*this' is the same object as 'rhs'. Note that if // 'rhs' is empty, then this shared pointer will also be empty after // the assignment. template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(const shared_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Make this shared pointer refer to and manage the same modifiable // object as the specified 'rhs' shared pointer to the (template // parameter) type 'COMPATIBLE_TYPE', using the same deleter as 'rhs' // and referring to '(ELEMENT_TYPE *)rhs.get()', and return a reference // to this modifiable shared pointer. If this shared pointer is // already managing a (possibly shared) object, then release the shared // reference to that object, and destroy it using its associated // deleter if this shared pointer held the last shared reference to // that object. Note that if 'rhs' is empty, then this shared pointer // will also be empty after the assignment. #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class COMPATIBLE_TYPE> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(shared_ptr<COMPATIBLE_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT; // Make this shared pointer refer to and manage the same modifiable // object as the specified 'rhs' shared pointer to the (template // parameter) type 'COMPATIBLE_TYPE', using the same deleter as 'rhs' // and referring to '(ELEMENT_TYPE *)rhs.get()', and return a reference // to this modifiable shared pointer. If this shared pointer is // already managing a (possibly shared) object, then release the shared // reference to that object, and destroy it using its associated // deleter if this shared pointer held the last shared reference to // that object. Reset 'rhs' to an empty state, not pointing to any // object, unless '*this' is the same object as 'rhs'. This function // does not exist unless a pointer to (template parameter) // 'COMPATIBLE_TYPE' is convertible to a pointer to the (template // parameter) 'ELEMENT_TYPE' of this 'shared_ptr'. Note that if 'rhs' // is empty, then this shared pointer will also be empty after the // assignment. #else template <class COMPATIBLE_TYPE> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(BloombergLP::bslmf::MovableRef<shared_ptr<COMPATIBLE_TYPE> > rhs) BSLS_KEYWORD_NOEXCEPT; // Make this shared pointer refer to and manage the same modifiable // object as the specified 'rhs' shared pointer to the (template // parameter) type 'COMPATIBLE_TYPE', using the same deleter as 'rhs' // and referring to '(ELEMENT_TYPE *)rhs.get()', and return a reference // to this modifiable shared pointer. If this shared pointer is // already managing a (possibly shared) object, then release the shared // reference to that object, and destroy it using its associated // deleter if this shared pointer held the last shared reference to // that object. Reset 'rhs' to an empty state, not pointing to any // object, unless '*this' is the same object as 'rhs'. This function // does not exist unless a pointer to (template parameter) // 'COMPATIBLE_TYPE' is convertible to a pointer to the (template // parameter) 'ELEMENT_TYPE' of this 'shared_ptr'. Note that if 'rhs' // is empty, then this shared pointer will also be empty after the // assignment. #endif template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(BloombergLP::bslma::ManagedPtr<COMPATIBLE_TYPE> rhs); // Transfer, to this shared pointer, ownership of the modifiable object // managed by the specified 'rhs' managed pointer to the (template // parameter) type 'COMPATIBLE_TYPE', and make this shared pointer // refer to '(ELEMENT_TYPE *)rhs.ptr()'. The deleter used in the 'rhs' // will be used to destroy the shared object when all references have // been released. The *default* *allocator* is used to allocate a // 'SharedPtrRep', if needed (users must use the copy-constructor and // swap instead of using this operator to supply an alternative // allocator). If this shared pointer is already managing a (possibly // shared) object, then release the reference to that shared object, // and destroy it using its associated deleter if this shared pointer // held the last shared reference to that object. Note that if 'rhs' // is empty, then this shared pointer will be empty after the // assignment. Also note that if 'rhs' owns a reference to another // shared object (due to a previous call to // 'shared_ptr<T>::managedPtr') then this 'shared_ptr' will adopt the // 'ManagedPtr's ownership of that shared object. #if defined(BSLS_LIBRARYFEATURES_HAS_CPP98_AUTO_PTR) template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(std::auto_ptr<COMPATIBLE_TYPE> rhs); // Transfer, to this shared pointer, ownership of the modifiable object // managed by the specified 'rhs' auto pointer to the (template // parameter) type 'COMPATIBLE_TYPE', and make this shared pointer // refer to '(ELEMENT_TYPE *)rhs.get()'. 'delete(autoPtr.release())' // will be called to destroy the shared object when all references have // been released. If this shared pointer is already managing a // (possibly shared) object, then release the reference to that shared // object, and destroy it using its associated deleter if this shared // pointer held the last shared reference to that object. Note that if // 'rhs' is empty, then this shared pointer will be empty after the // assignment. #endif #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_UNIQUE_PTR) template <class COMPATIBLE_TYPE, class UNIQUE_DELETER> typename enable_if< is_convertible< typename std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>::pointer, ELEMENT_TYPE *>::value, shared_ptr&>::type operator=(std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>&& rhs); // Transfer, to this shared pointer, ownership of the object managed by // the specified 'rhs' unique pointer to the (template parameter) type // 'COMPATIBLE_TYPE', and make this shared pointer refer to // '(ELEMENT_TYPE *)rhs.get()'. The deleter of 'rhs' will be called to // destroy the shared object when all references have been released. // If this shared pointer is already managing a (possibly shared) // object, then release the reference to that shared object, and // destroy it using its associated deleter if this shared pointer held // the last shared reference to that object. This function does not // exist unless 'unique_ptr<COMPATIBLE_TYPE, DELETER>::pointer' is // convertible to 'ELEMENT_TYPE *'. Note that if 'rhs' is empty, then // this shared pointer will be empty after the assignment. Also note // that this function creates a 'shared_ptr' with an unspecified // deleter type that satisfies this contract; the C++11 standard // specifies the exact deleter that should be in use after assignment, // so this implementation may be non-conforming. #endif void reset() BSLS_KEYWORD_NOEXCEPT; // Reset this shared pointer to the empty state. If this shared // pointer is managing a (possibly shared) object, then release the // reference to the shared object, calling the associated deleter to // destroy the shared object if this shared pointer is the last shared // reference. template <class COMPATIBLE_TYPE> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type reset(COMPATIBLE_TYPE *ptr); // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address and to refer to '(ELEMENT_TYPE *)ptr'. If this shared // pointer is already managing a (possibly shared) object, then, unless // an exception is thrown allocating memory to manage 'ptr', release // the reference to the shared object, calling the associated deleter // to destroy the shared object if this shared pointer is the last // reference. The currently installed default allocator is used to // allocate the internal representation of this shared pointer, and the // shared object will be destroyed by a call to 'delete ptr' when all // references have been released. If an exception is thrown allocating // the internal representation, then 'delete ptr' is called and this // shared pointer retains ownership of its original object. If // 'COMPATIBLE_TYPE*' is not implicitly convertible to 'ELEMENT_TYPE*', // then a compiler diagnostic will be emitted indicating the error. // Note that if 'ptr' is 0, then this shared pointer will still // allocate an internal representation to share ownership of that empty // state, which will be reclaimed when the last reference is destroyed. template <class COMPATIBLE_TYPE, class DELETER> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type reset(COMPATIBLE_TYPE *ptr, DELETER deleter); // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address, refer to '(ELEMENT_TYPE *)ptr', and use the specified // 'deleter' to delete the shared object when all references have been // released. If this shared pointer is already managing a (possibly // shared) object, then unless an exception is thrown allocating memory // to manage 'ptr', release the reference to the shared object, calling // the associated deleter to destroy the shared object if this shared // pointer is the last reference. If 'DELETER' is an object type, then // 'deleter' is assumed to be a function-like deleter that may be // invoked to destroy the object referred to by a single argument of // type 'COMPATIBLE_TYPE *' (i.e., 'deleter(ptr)' will be called to // destroy the shared object). If 'DELETER' is a pointer type that is // not a function pointer, then 'deleter' shall be a pointer to a // factory object that exposes a member function that can be invoked as // 'deleteObject(ptr)' that will be called to destroy the object at the // 'ptr' address (i.e., 'deleter->deleteObject(ptr)' will be called to // delete the shared object). (See the "Deleters" section in the // component-level documentation.) If 'DELETER' is also a pointer to // 'bslma::Allocator' or to a class derived from 'bslma::Allocator', // then that allocator will also be used to allocate and destroy the // internal representation of this shared pointer when all references // have been released; otherwise, the currently installed default // allocator is used to allocate and destroy the internal // representation of this shared pointer when all references have been // released. If an exception is thrown allocating the internal // representation, then 'deleter(ptr)' is called (or // 'deleter->deleteObject(ptr)' for factory-type deleters) and this // shared pointer retains ownership of its original object. If // 'COMPATIBLE_TYPE*' is not implicitly convertible to 'ELEMENT_TYPE*', // then a compiler diagnostic will be emitted indicating the error. // Note that, for factory deleters, 'deleter' must remain valid until // all references to 'ptr' have been released. If 'ptr' is 0, then an // internal representation will still be allocated, and this shared // pointer will share ownership of a copy of 'deleter'. Further note // that this function is logically equivalent to: //.. // *this = shared_ptr<ELEMENT_TYPE>(ptr, deleter); //.. template <class COMPATIBLE_TYPE, class DELETER, class ALLOCATOR> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type reset(COMPATIBLE_TYPE *ptr, DELETER deleter, ALLOCATOR basicAllocator); // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address, refer to '(ELEMENT_TYPE *)ptr' and use the specified // 'deleter' to delete the shared object when all references have been // released. Use the specified 'basicAllocator' to allocate and // deallocate the internal representation of the shared pointer. If // this shared pointer is already managing a (possibly shared) object, // then, unless an exception is thrown allocating memory to manage // 'ptr', release the shared reference to that shared object, and // destroy it using its associated deleter if this shared pointer held // the last shared reference to that object. If 'DELETER' is a // reference type, then 'deleter' is assumed to be a function-like // deleter that may be invoked to destroy the object referred to by a // single argument of type 'COMPATIBLE_TYPE *' (i.e., 'deleter(ptr)' // will be called to destroy the shared object). If 'DELETER' is a // pointer type, then 'deleter' is assumed to be a pointer to a factory // object that exposes a member function that can be invoked as // 'deleteObject(ptr)' that will be called to destroy the object at the // 'ptr' address (i.e., 'deleter->deleteObject(ptr)' will be called to // delete the shared object). (See the "Deleters" section in the // component-level documentation.) If an exception is thrown // allocating the internal representation, then 'deleter(ptr)' is // called (or 'deleter->deleteObject(ptr)' for factory-type deleters) // and this shared pointer retains ownership of its original object. // The behavior is undefined unless 'deleter(ptr)' is a well-defined // expression (or 'deleter->deleteObject(ptr)' for factory-type // deleters), and unless the copy constructor for 'deleter' does not // throw an exception. If 'COMPATIBLE_TYPE *' is not implicitly // convertible to 'ELEMENT_TYPE *', then a compiler diagnostic will be // emitted indicating the error. Note that, for factory deleters, the // 'deleter' must remain valid until all references to 'ptr' have been // released. Also note that if 'ptr' is 0, then an internal // representation will still be allocated, and this shared pointer will // share ownership of a copy of 'deleter'. Further note that this // function is logically equivalent to: //.. // *this = shared_ptr<ELEMENT_TYPE>(ptr, deleter, basicAllocator); //.. template <class ANY_TYPE> void reset(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *ptr); // Modify this shared pointer to manage the same modifiable object (if // any) as the specified 'source' shared pointer to the (template // parameter) type 'ANY_TYPE', and refer to the modifiable object at // the specified 'ptr' address (i.e., make this shared pointer an // "alias" of 'source'). If this shared pointer is already managing a // (possibly shared) object, then release the reference to the shared // object, calling the associated deleter to destroy the shared object // if this shared pointer is the last reference. Note that typically // the objects referred to by 'source' and 'ptr' have identical // lifetimes (e.g., one might be a part of the other), so that the // deleter for 'source' will destroy them both, but do not necessarily // have the same type. Also note that if 'source' is empty, then this // shared pointer will be reset to an empty state, even if 'ptr' is not // null (in which case this empty shared pointer will refer to the same // object as 'ptr'). Also note that if 'ptr' is null and 'source' is // not empty, then this shared pointer will be reset to a // (reference-counted) null pointer alias. Further note that the // behavior of this method is the same as 'loadAlias(source, ptr)'. // Finally note that this is a non-standard BDE extension to the C++ // Standard 'shared_ptr' interface, which does not provide an alias // overload for the 'reset' function. void swap(shared_ptr& other) BSLS_KEYWORD_NOEXCEPT; // Efficiently exchange the states of this shared pointer and the // specified 'other' shared pointer such that each will refer to the // object formerly referred to by the other and each will manage the // object formerly managed by the other. // ADDITIONAL BSL MANIPULATORS void createInplace(); // Create "in-place" in a large enough contiguous memory region both an // internal representation for this shared pointer and a // default-constructed object of 'ELEMENT_TYPE', and make this shared // pointer refer to the newly-created 'ELEMENT_TYPE' object. The // currently installed default allocator is used to supply memory. If // an exception is thrown during allocation or construction of the // 'ELEMENT_TYPE' object, this shared pointer will be unchanged. // Otherwise, if this shared pointer is already managing a (possibly // shared) object, then release the shared reference to that shared // object, and destroy it using its associated deleter if this shared // pointer held the last shared reference to that object. #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14 template <class... ARGS> void createInplace(BloombergLP::bslma::Allocator *basicAllocator, ARGS&&... args); // Create "in-place" in a large enough contiguous memory region, using // the specified 'basicAllocator' to supply memory, both an internal // representation for this shared pointer and an object of // 'ELEMENT_TYPE' using the 'ELEMENT_TYPE' constructor that takes the // specified 'args...' arguments, and make this shared pointer refer to // the newly-created 'ELEMENT_TYPE' object. If an exception is thrown // during the construction of the 'ELEMENT_TYPE' object, this shared // pointer will be unchanged. Otherwise, if this shared pointer is // already managing a (possibly shared) object, then release the shared // reference to that shared object, and destroy it using its associated // deleter if this shared pointer held the last shared reference to // that object. Note that the allocator argument is *not* implicitly // passed to the constructor for 'ELEMENT_TYPE'; to construct an object // of 'ELEMENT_TYPE' with an allocator, pass the allocator as one of // the arguments (typically the last argument), or assign with a // 'shared_ptr' created using the standard 'allocate_shared' function. #endif template <class ANY_TYPE> void loadAlias(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *object); // [!DEPRECATED!] Use 'reset' instead. // // Modify this shared pointer to manage the same modifiable object (if // any) as the specified 'source' shared pointer to the (template // parameter) type 'ANY_TYPE', and refer to the modifiable object at // the specified 'object' address (i.e., make this shared pointer an // "alias" of 'source'). If this shared pointer is already managing a // (possibly shared) object, then release the shared reference to that // shared object, and destroy it using its associated deleter if this // shared pointer held the last shared reference to that object. Note // that typically the objects referred to by 'source' and 'object' have // identical lifetimes (e.g., one might be a part of the other), so // that the deleter for 'source' will destroy them both, but they do // not necessarily have the same type. Also note that if 'source' is // empty, then this shared pointer will be reset to an empty state, // even if 'object' is not null (in which case this empty shared // pointer will refer to the same object as 'object'). Also note that // if 'object' is null and 'source' is not empty, then this shared // pointer will be reset to a (reference-counted) null pointer alias. // Also note that this function is logically equivalent to: //.. // *this = shared_ptr<ELEMENT_TYPE>(source, object); //.. // Further note that the behavior of this method is the same as // 'reset(source, object)'. pair<ELEMENT_TYPE *, BloombergLP::bslma::SharedPtrRep *> release() BSLS_KEYWORD_NOEXCEPT; // Return the pair consisting of the addresses of the modifiable // 'ELEMENT_TYPE' object referred to, and the representation shared by, // this shared pointer, and reset this shared pointer to the empty // state, referring to no object, with no effect on the representation. // The reference counter is not modified nor is the shared object // deleted; if the reference count of the representation is greater // than one, then it is not safe to release the representation (thereby // destroying the shared object), but it is always safe to create // another shared pointer with the representation using the constructor // with the signature // 'shared_ptr(ELEMENT_TYPE *ptr, // BloombergLP::bslma::SharedPtrRep *rep)'. // Note that this function returns a pair of null pointers if this // shared pointer is empty. #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY MANIPULATORS void clear() BSLS_KEYWORD_NOEXCEPT; // [!DEPRECATED!] Use 'reset' instead. // // Reset this shared pointer to the empty state. If this shared // pointer is managing a (possibly shared) object, then release the // reference to the shared object, calling the associated deleter to // destroy the shared object if this shared pointer is the last // reference. Note that the behavior of this method is the same as // 'reset()'. template <class COMPATIBLE_TYPE> void load(COMPATIBLE_TYPE *ptr); // [!DEPRECATED!] Use 'reset' instead. // // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address and to refer to '(ELEMENT_TYPE *)ptr'. If this shared // pointer is already managing a (possibly shared) object, then, unless // an exception is thrown allocating memory to manage 'ptr', release // the reference to the shared object, calling the associated deleter // to destroy the shared object if this shared pointer is the last // reference. The currently installed default allocator is used to // allocate the internal representation of this shared pointer, and the // shared object will be destroyed by a call to 'delete ptr' when all // references have been released. If an exception is thrown allocating // the internal representation, then 'delete ptr' is called and this // shared pointer retains ownership of its original object. If // 'COMPATIBLE_TYPE*' is not implicitly convertible to 'ELEMENT_TYPE*', // then a compiler diagnostic will be emitted indicating the error. // Note that if 'ptr' is 0, then this shared pointer will still // allocate an internal representation to share ownership of that empty // state, which will be reclaimed when the last reference is destroyed. // Also note also that the behavior of this method is the same as // 'reset(ptr)'. template <class COMPATIBLE_TYPE> void load(COMPATIBLE_TYPE *ptr, BloombergLP::bslma::Allocator *basicAllocator); // [!DEPRECATED!] Use 'reset' instead. // // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address and to refer to '(ELEMENT_TYPE *)ptr'. If this shared // pointer is already managing a (possibly shared) object, then, unless // an exception is thrown allocating memory to manage 'ptr', release // the reference to the shared object, calling the associated deleter // to destroy the shared object if this shared pointer is the last // reference. Use the specified 'basicAllocator' to allocate the // internal representation of this shared pointer and to destroy the // shared object when all references have been released; if // 'basicAllocator' is 0, the currently installed default allocator is // used. If an exception is thrown allocating the internal // representation, then destroy '*ptr' with a call to // 'alloc->deleteObject(ptr)' where 'alloc' is the chosen allocator, // and this shared pointer retains ownership of its original object. // If 'COMPATIBLE_TYPE *' is not implicitly convertible to // 'ELEMENT_TYPE *', then a compiler diagnostic will be emitted // indicating the error. Note that if 'ptr' is 0, then this shared // pointer will still allocate an internal representation to share // ownership of that empty state, which will be reclaimed when the last // reference is destroyed. Also note that this function is logically // equivalent to: //.. // *this = shared_ptr<ELEMENT_TYPE>(ptr, basicAllocator); //.. template <class COMPATIBLE_TYPE, class DELETER> void load(COMPATIBLE_TYPE *ptr, const DELETER& deleter, BloombergLP::bslma::Allocator *basicAllocator); // [!DEPRECATED!] Use 'reset' instead. // // Modify this shared pointer to manage the modifiable object of the // (template parameter) type 'COMPATIBLE_TYPE' at the specified 'ptr' // address, refer to '(ELEMENT_TYPE *)ptr' and use the specified // 'deleter' to delete the shared object when all references have been // released. Use the specified 'basicAllocator' to allocate and // deallocate the internal representation of the shared pointer. If // 'basicAllocator' is 0, the currently installed default allocator is // used. If this shared pointer is already managing a (possibly // shared) object, then, unless an exception is thrown creating storage // to manage 'ptr', release the shared reference to that shared object, // and destroy it using its associated deleter if this shared pointer // held the last shared reference to that object. If 'DELETER' is a // reference type, then 'deleter' is assumed to be a function-like // deleter that may be invoked to destroy the object referred to by a // single argument of type 'COMPATIBLE_TYPE *' (i.e., 'deleter(ptr)' // will be called to destroy the shared object). If 'DELETER' is a // pointer type, then 'deleter' is assumed to be a pointer to a factory // object that exposes a member function that can be invoked as // 'deleteObject(ptr)' that will be called to destroy the object at the // 'ptr' address (i.e., 'deleter->deleteObject(ptr)' will be called to // delete the shared object). (See the "Deleters" section in the // component-level documentation.) If an exception is thrown // allocating the internal representation, then 'deleter(ptr)' is // called (or 'deleter->deleteObject(ptr)' for factory-type deleters) // and this shared pointer retains ownership of its original object. // The behavior is undefined unless 'deleter(ptr)' is a well-defined // expression (or 'deleter->deleteObject(ptr)' for factory-type // deleters), and unless the copy constructor for 'deleter' does not // throw an exception. If 'COMPATIBLE_TYPE *' is not implicitly // convertible to 'ELEMENT_TYPE *', then a compiler diagnostic will be // emitted indicating the error. Note that, for factory deleters, the // 'deleter' must remain valid until all references to 'ptr' have been // released. Also note that if 'ptr' is 0, then an internal // representation will still be allocated, and this shared pointer will // share ownership of a copy of 'deleter'. Further note that this // function is logically equivalent to: //.. // *this = shared_ptr<ELEMENT_TYPE>(ptr, deleter, basicAllocator); //.. #endif // BDE_OMIT_INTERNAL_DEPRECATED // ACCESSORS operator BoolType() const BSLS_KEYWORD_NOEXCEPT; // Return a value of an "unspecified bool" type that evaluates to // 'false' if this shared pointer does not refer to an object, and // 'true' otherwise. Note that this conversion operator allows a // shared pointer to be used within a conditional context (e.g., within // an 'if' or 'while' statement), but does *not* allow shared pointers // to unrelated types to be compared (e.g., via '<' or '>'). typename add_lvalue_reference<ELEMENT_TYPE>::type operator*() const BSLS_KEYWORD_NOEXCEPT; // Return a reference providing modifiable access to the object // referred to by this shared pointer. The behavior is undefined // unless this shared pointer refers to an object, and 'ELEMENT_TYPE' // is not (potentially 'const' or 'volatile' qualified) 'void'. ELEMENT_TYPE *operator->() const BSLS_KEYWORD_NOEXCEPT; // Return the address providing modifiable access to the object // referred to by this shared pointer, or 0 if this shared pointer does // not refer to an object. Note that applying this operator // conventionally (e.g., to invoke a method) to an shared pointer that // does not refer to an object will result in undefined behavior. element_type *get() const BSLS_KEYWORD_NOEXCEPT; // Return the address providing modifiable access to the object // referred to by this shared pointer, or 0 if this shared pointer does // not refer to an object. typename add_lvalue_reference<element_type>::type operator[](ptrdiff_t index) const; // Return a reference providing modifiable access to the object at the // specified 'index' offset in the object referred to by this shared // pointer. The behavior is undefined unless this shared pointer is // not empty, 'ELEMENT_TYPE' is not 'void' (a compiler error will be // generated if this operator is instantiated within the // 'shared_ptr<void>' class), and this shared pointer refers to an // array of 'ELEMENT_TYPE' objects. Instead of 'element_type &', we // use 'add_lvalue_reference<element_type>::type' for the return type // because that allows people to instantiate 'shared_ptr<cv_void>', as // long as they don't use this method. Note that this method is // logically equivalent to '*(get() + index)'. template<class ANY_TYPE> bool owner_before(const shared_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT; template<class ANY_TYPE> bool owner_before(const weak_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the // 'BloombergLP::bslma::SharedPtrRep' object used by this shared // pointer is ordered before the address of the // 'BloombergLP::bslma::SharedPtrRep' object used by the specified // 'other' shared pointer under the total ordering defined by // 'std::less<BloombergLP::bslma::SharedPtrRep *>', and 'false' // otherwise. BSLS_DEPRECATE_FEATURE("bsl", "deprecated_cpp17_standard_library_features", "do not use") bool unique() const BSLS_KEYWORD_NOEXCEPT; // Return 'true' if this shared pointer is not empty and does not share // ownership of the object it managed with any other shared pointer, // and 'false' otherwise. Note that a shared pointer with a custom // deleter can refer to a null pointer without being empty, and so may // be 'unique'. Also note that the result of this function may not be // reliable in a multi-threaded program, where a weak pointer may be // locked on another thread. // // DEPRECATED: This function is deprecated in C++17 because its // correctness is not guaranteed since the value returned by the used // 'use_count' function is approximate. long use_count() const BSLS_KEYWORD_NOEXCEPT; // Return a "snapshot" of the number of shared pointers (including this // one) that share ownership of the object managed by this shared // pointer. Note that 0 is returned if this shared pointer is empty. // Also note that any result other than 0 may be unreliable in a // multi-threaded program, where another pointer sharing ownership in a // different thread may be copied or destroyed, or a weak pointer may // be locked in the case that 1 is returned (that would otherwise // indicate unique ownership). // ADDITIONAL BSL ACCESSORS BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE> managedPtr() const; // Return a managed pointer that refers to the same object as this // shared pointer. If this shared pointer is not empty, and is not // null, then increment the shared count on the shared object, and give // the managed pointer a deleter that decrements the reference count // for the shared object. Note that if this 'shared_ptr' is reference- // counting a null pointer, the empty 'bslma::ManagedPtr' returned will // not participate in that shared ownership. BloombergLP::bslma::SharedPtrRep *rep() const BSLS_KEYWORD_NOEXCEPT; // Return the address providing modifiable access to the // 'BloombergLP::bslma::SharedPtrRep' object used by this shared // pointer, or 0 if this shared pointer is empty. #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY ACCESSORS int numReferences() const BSLS_KEYWORD_NOEXCEPT; // [!DEPRECATED!] Use 'use_count' instead. // // Return a "snapshot" of the number of shared pointers (including this // one) that share ownership of the object managed by this shared // pointer. Note that the behavior of this function is the same as // 'use_count', and the result may be unreliable in multi-threaded code // for the same reasons. ELEMENT_TYPE *ptr() const BSLS_KEYWORD_NOEXCEPT; // [!DEPRECATED!] Use 'get' instead. // // Return the address providing modifiable access to the object // referred to by this shared pointer, or 0 if this shared pointer does // not refer to an object. Note that the behavior of this function is // the same as 'get'. #endif // BDE_OMIT_INTERNAL_DEPRECATED }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD // CLASS TEMPLATE DEDUCTION GUIDES // The obvious deduction guide: // template <class T> // shared_ptr(T*) -> shared_ptr<T>; // is not provided because there's no way to distinguish from T* and T[]. template<class ELEMENT_TYPE> shared_ptr(weak_ptr<ELEMENT_TYPE>) -> shared_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'bsl::weak_ptr' supplied to the constructor of // 'shared_ptr'. template<class ELEMENT_TYPE, class DELETER> shared_ptr(std::unique_ptr<ELEMENT_TYPE, DELETER>) -> shared_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'std::unique_ptr' supplied to the constructor of // 'shared_ptr'. template<class ELEMENT_TYPE, class DELETER, class ALLOC, class = typename bsl::enable_if_t< bsl::is_convertible_v<ALLOC *, BloombergLP::bslma::Allocator *>> > shared_ptr(std::unique_ptr<ELEMENT_TYPE, DELETER>, ALLOC *) -> shared_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'std::unique_ptr' supplied to the constructor of // 'shared_ptr'. This guide does not participate in deduction unless the // specified 'ALLOC' inherits from 'bslma::Allocator'. // Deduction guides for 'auto_ptr' and 'auto_ptr_ref' are deliberately not // provided, since auto_ptr has been removed from C++17. template<class ELEMENT_TYPE> shared_ptr(BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE>) -> shared_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'bslma::ManagedPtr' supplied to the constructor of // 'shared_ptr'. template<class ELEMENT_TYPE, class ALLOC, class = typename bsl::enable_if_t< bsl::is_convertible_v<ALLOC *, BloombergLP::bslma::Allocator *>> > shared_ptr(BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE>, ALLOC *) -> shared_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'bslma::ManagedPtr' supplied to the constructor of // 'shared_ptr'. This guide does not participate in deduction unless the // specified 'ALLOC' inherits from 'bslma::Allocator'. #endif // FREE OPERATORS template <class LHS_TYPE, class RHS_TYPE> bool operator==(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer refers to the same // object (if any) as that referred to by the specified 'rhs' shared // pointer (if any), and 'false' otherwise; a compiler diagnostic will be // emitted indicating the error unless a (raw) pointer to 'LHS_TYPE' can // be compared to a (raw) pointer to 'RHS_TYPE'. Note that two shared // pointers that compare equal do not necessarily manage the same object // due to aliasing. template <class LHS_TYPE, class RHS_TYPE> bool operator!=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer does not refer to // the same object (if any) as that referred to by the specified 'rhs' // shared pointer (if any), and 'false' otherwise; a compiler diagnostic // will be emitted indicating the error unless a (raw) pointer to // 'LHS_TYPE' can be compared to a (raw) pointer to 'RHS_TYPE'. Note that // two shared pointers that do not compare equal may manage the same object // due to aliasing. template<class LHS_TYPE, class RHS_TYPE> bool operator<(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object that the specified 'lhs' // shared pointer refers to is ordered before the address of the object // that the specified 'rhs' shared pointer refers to under the total // ordering supplied by 'std::less<T *>', where 'T *' is the composite // pointer type of 'LHS_TYPE *' and 'RHS_TYPE *', and 'false' otherwise. template<class LHS_TYPE, class RHS_TYPE> bool operator>(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object that the specified 'lhs' // shared pointer refers to is ordered after the address of the object // that the specified 'rhs' shared pointer refers to under the total // ordering supplied by 'std::less<T *>', where 'T *' is the composite // pointer type of 'LHS_TYPE *' and 'RHS_TYPE *', and 'false' otherwise. template<class LHS_TYPE, class RHS_TYPE> bool operator<=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer refers to the same // object as the specified 'rhs' shared pointer, or if the address of the // object referred to by 'lhs' (if any) is ordered before the address of // the object referred to by 'rhs' (if any) under the total ordering // supplied by 'std::less<T *>', where 'T *' is the composite pointer type // of 'LHS_TYPE *' and 'RHS_TYPE *', and 'false' otherwise. template<class LHS_TYPE, class RHS_TYPE> bool operator>=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer refers to the same // object as the specified 'rhs' shared pointer, or if the address of the // object referred to by 'lhs' (if any) is ordered after the address of the // object referred to by 'rhs' (if any) under the total ordering supplied // by 'std::less<T *>', where 'T *' is the composite pointer type of // 'LHS_TYPE *' and 'RHS_TYPE *', and 'false' otherwise. template <class LHS_TYPE> bool operator==(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer does not refer to an // object, and 'false' otherwise. template <class RHS_TYPE> bool operator==(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'rhs' shared pointer does not refer to an // object, and 'false' otherwise. template <class LHS_TYPE> bool operator!=(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer refers to an object, // and 'false' otherwise. template <class RHS_TYPE> bool operator!=(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'rhs' shared pointer refers to an object, // and 'false' otherwise. template <class LHS_TYPE> bool operator<(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object referred to by the specified // 'lhs' shared pointer is ordered before the null-pointer value under the // total ordering supplied by 'std::less<LHS_TYPE *>', and 'false' // otherwise. template <class RHS_TYPE> bool operator<(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object referred to by the specified // 'rhs' shared pointer is ordered after the null-pointer value under the // total ordering supplied by 'std::less<RHS_TYPE *>', and 'false' // otherwise. template <class LHS_TYPE> bool operator<=(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer does not refer to an // object, or if the address of the object referred to by 'lhs' is ordered // before the null-pointer value under the total ordering supplied by // 'std::less<LHS_TYPE *>', and 'false' otherwise. template <class RHS_TYPE> bool operator<=(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'rhs' shared pointer does not refer to an // object, or if the address of the object referred to by 'rhs' is ordered // after the null-pointer value under the total ordering supplied by // 'std::less<RHS_TYPE *>', and 'false' otherwise. template <class LHS_TYPE> bool operator>(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object referred to by the specified // 'lhs' shared pointer is ordered after the null-pointer value under the // total ordering supplied by 'std::less<LHS_TYPE *>', and 'false' // otherwise. template <class RHS_TYPE> bool operator>(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the object referred to by the specified // 'rhs' shared pointer is ordered before the null-pointer value under the // total ordering supplied by 'std::less<RHS_TYPE *>', and 'false' // otherwise. template <class LHS_TYPE> bool operator>=(const shared_ptr<LHS_TYPE>& lhs, nullptr_t) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'lhs' shared pointer does not refer to an // object, or if the address of the object referred to by 'lhs' is ordered // after the null-pointer value under the total ordering supplied by // 'std::less<LHS_TYPE *>', and 'false' otherwise. template <class RHS_TYPE> bool operator>=(nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the specified 'rhs' shared pointer does not refer to an // object, or if the address of the object referred to by 'rhs' is ordered // before the null-pointer value under the total ordering supplied by // 'std::less<RHS_TYPE *>', and 'false' otherwise. template<class CHAR_TYPE, class CHAR_TRAITS, class ELEMENT_TYPE> std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>& operator<<(std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>& stream, const shared_ptr<ELEMENT_TYPE>& rhs); // Print to the specified 'stream' the address of the shared object // referred to by the specified 'rhs' shared pointer and return a reference // to the modifiable 'stream'. // ASPECTS template <class HASHALG, class ELEMENT_TYPE> void hashAppend(HASHALG& hashAlg, const shared_ptr<ELEMENT_TYPE>& input); // Pass the address of the object referred to by the specified 'input' // shared pointer to the specified 'hashAlg' hashing algorithm of (template // parameter) type 'HASHALG'. template <class ELEMENT_TYPE> void swap(shared_ptr<ELEMENT_TYPE>& a, shared_ptr<ELEMENT_TYPE>& b) BSLS_KEYWORD_NOEXCEPT; // Efficiently exchange the states of the specified 'a' and 'b' shared // pointers such that each will refer to the object formerly referred to by // the other, and each will manage the object formerly managed by the // other. // STANDARD FREE FUNCTIONS template<class DELETER, class ELEMENT_TYPE> DELETER *get_deleter(const shared_ptr<ELEMENT_TYPE>& p) BSLS_KEYWORD_NOEXCEPT; // Return the address of deleter used by the specified 'p' shared pointer // if the (template parameter) type 'DELETER' is the type of the deleter // installed in 'p', and a null pointer value otherwise. // STANDARD CAST FUNCTIONS template<class TO_TYPE, class FROM_TYPE> shared_ptr<TO_TYPE> const_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'shared_ptr<TO_TYPE>' object sharing ownership of the same // object as the specified 'source' shared pointer to the (template // parameter) 'FROM_TYPE', and referring to // 'const_cast<TO_TYPE *>(source.get())'. Note that if 'source' cannot be // 'const'-cast to 'TO_TYPE *', then a compiler diagnostic will be emitted // indicating the error. template<class TO_TYPE, class FROM_TYPE> shared_ptr<TO_TYPE> dynamic_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'shared_ptr<TO_TYPE>' object sharing ownership of the same // object as the specified 'source' shared pointer to the (template // parameter) 'FROM_TYPE', and referring to // 'dynamic_cast<TO_TYPE*>(source.get())'. If 'source' cannot be // dynamically cast to 'TO_TYPE *', then an empty 'shared_ptr<TO_TYPE>' // object is returned. template<class TO_TYPE, class FROM_TYPE> shared_ptr<TO_TYPE> static_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'shared_ptr<TO_TYPE>' object sharing ownership of the same // object as the specified 'source' shared pointer to the (template // parameter) 'FROM_TYPE', and referring to // 'static_cast<TO_TYPE *>(source.get())'. Note that if 'source' cannot be // statically cast to 'TO_TYPE *', then a compiler diagnostic will be // emitted indicating the error. template<class TO_TYPE, class FROM_TYPE> shared_ptr<TO_TYPE> reinterpret_pointer_cast( const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'shared_ptr<TO_TYPE>' object sharing ownership of the same // object as the specified 'source' shared pointer to the (template // parameter) 'FROM_TYPE', and referring to // 'reinterpret_cast<TO_TYPE *>(source.get())'. Note that if 'source' // cannot be reinterpret_cast-ed to 'TO_TYPE *', then a compiler diagnostic // will be emitted indicating the error. // STANDARD FACTORY FUNCTIONS #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14 template<class ELEMENT_TYPE, class ALLOC, class... ARGS> # if defined(BSLSTL_SHAREDPTR_NO_PARTIAL_ORDER_ON_ALLOCATOR_POINTER) // work-around for gcc variadic template bug - confirm not fixed by gcc 9 typename enable_if<!is_pointer<ALLOC>::value && !is_array<ELEMENT_TYPE>::value, shared_ptr<ELEMENT_TYPE> >::type # else typename enable_if<!is_array<ELEMENT_TYPE>::value, shared_ptr<ELEMENT_TYPE> >::type // shared_ptr<ELEMENT_TYPE> # endif allocate_shared(ALLOC basicAllocator, ARGS&&... args); // Return a 'shared_ptr' object referring to and managing a new // 'ELEMENT_TYPE' object. The specified 'basicAllocator' will be used to // supply a single contiguous region of memory holding the returned shared // pointer's internal representation and the new 'ELEMENT_TYPE' object, // which is initialized by calling 'allocator_traits<ALLOC>::construct' // passing 'basicAllocator', an 'ELEMENT_TYPE *' pointer to space for the // new shared object, and the specified arguments // 'std::forward<ARGS>(args)...'. template<class ELEMENT_TYPE, class ALLOC, class... ARGS> typename enable_if<!is_array<ELEMENT_TYPE>::value, shared_ptr<ELEMENT_TYPE> >::type allocate_shared(ALLOC *basicAllocator, ARGS&&... args); // Return a 'shared_ptr' object referring to and managing a new // 'ELEMENT_TYPE' object. The specified 'basicAllocator' will be used to // supply a single contiguous region of memory holding the returned shared // pointer's internal representation and the new 'ELEMENT_TYPE' object, // which is initialized using the 'ELEMENT_TYPE' constructor that takes the // specified arguments 'std::forward<ARGS>(args)...'. If 'ELEMENT_TYPE' // uses 'bslma' allocators, then 'basicAllocator' is passed as an extra // argument in the final position. If 'basicAllocator' is 0, then the // default allocator will be used instead, and passed as the allocator, // when appropriate, to the 'ELEMENT_TYPE' constructor. template<class ELEMENT_TYPE, class... ARGS> typename enable_if<!is_array<ELEMENT_TYPE>::value, shared_ptr<ELEMENT_TYPE> >::type make_shared(ARGS&&... args); // Return a 'shared_ptr' object referring to and managing a new // 'ELEMENT_TYPE' object. The default allocator will be used to supply a // single contiguous region of memory holding the returned shared pointer's // internal representation and the new 'ELEMENT_TYPE' object, which is // initialized using the 'ELEMENT_TYPE' constructor that takes the // specified arguments 'std::forward<ARGS>(args)...'. If 'ELEMENT_TYPE' // uses 'bslma' allocators, then the default allocator is passed as an // extra argument in the final position. #endif // ============== // class weak_ptr // ============== template <class ELEMENT_TYPE> class weak_ptr { // This 'class' provides a mechanism to create weak references to // reference-counted shared ('shared_ptr') objects. A weak reference // provides conditional access to a shared object managed by a // 'shared_ptr', but, unlike a shared (or "strong") reference, does not // affect the shared object's lifetime. // DATA ELEMENT_TYPE *d_ptr_p; // pointer to the referenced // object BloombergLP::bslma::SharedPtrRep *d_rep_p; // pointer to the representation // object that manages the // shared object (held, not // owned) // PRIVATE MANIPULATORS void privateAssign(BloombergLP::bslma::SharedPtrRep *rep, ELEMENT_TYPE *target); // Release weak ownership of the currently managed shared pointer rep // and assign to this weak pointer weak ownership of the specified // shared pointer 'rep', aliasing the specified 'target' pointer. // FRIENDS template <class COMPATIBLE_TYPE> friend class weak_ptr; // This 'friend' declaration provides access to the internal data // members while constructing a weak pointer from a weak pointer of a // different type. friend struct BloombergLP::bslstl::SharedPtr_ImpUtil; public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(weak_ptr<ELEMENT_TYPE>, bsl::is_nothrow_move_constructible); // TYPES typedef typename bsl::remove_extent<ELEMENT_TYPE>::type element_type; // For weak pointers to non-array types, 'element_type' is an alias to // the 'ELEMENT_TYPE' template parameter. Otherwise, it is an alias to // the type contained in the array. // CREATORS BSLS_KEYWORD_CONSTEXPR weak_ptr() BSLS_KEYWORD_NOEXCEPT; // Create a weak pointer in the empty state and referring to no object, // i.e., a weak pointer having no representation. weak_ptr(BloombergLP::bslmf::MovableRef<weak_ptr> original) BSLS_KEYWORD_NOEXCEPT; // Create a weak pointer that refers to the same object (if any) as the // specified 'original' weak pointer, and reset 'original' to an empty // state. #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> weak_ptr(weak_ptr<COMPATIBLE_TYPE>&& other) BSLS_KEYWORD_NOEXCEPT; #else template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> weak_ptr(BloombergLP::bslmf::MovableRef<weak_ptr<COMPATIBLE_TYPE> > other) BSLS_KEYWORD_NOEXCEPT; #endif // Create a weak pointer that refers to the same object (if any) as the // specified 'other' weak pointer, and reset 'original' to an empty // state. Note that this operation does not involve any change to // reference counts. weak_ptr(const weak_ptr& original) BSLS_KEYWORD_NOEXCEPT; // Create a weak pointer that refers to the same object (if any) as the // specified 'original' weak pointer, and increment the number of weak // references to the object managed by 'original' (if any). Note that // if 'original' is in the empty state, this weak pointer will be // initialized to the empty state. template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> weak_ptr(const shared_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT; // IMPLICIT template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE> weak_ptr(const weak_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT; // IMPLICIT // Create a weak pointer that refers to the same object (if any) as the // specified 'other' (shared or weak) pointer of the (template // parameter) 'COMPATIBLE_TYPE', and increment the number of weak // references to the object managed by 'other' (if any). If // 'COMPATIBLE_TYPE *' is not implicitly convertible to // 'ELEMENT_TYPE *', then a compiler diagnostic will be emitted. Note // that if 'other' is in the empty state, this weak pointer will be // initialized to the empty state. ~weak_ptr(); // Destroy this weak pointer object. If this weak pointer manages a // (possibly shared) object, release the weak reference to that object. // MANIPULATORS weak_ptr& operator=(BloombergLP::bslmf::MovableRef<weak_ptr> rhs) BSLS_KEYWORD_NOEXCEPT; // Make this weak pointer refer to the same object (if any) as the // specified 'rhs' weak pointer. If 'rhs' is not a reference to this // weak pointer, decrement the number of weak references to the object // this weak pointer managed (if any), and reset 'rhs' to an empty // state. Return a reference providing modifiable access to this weak // pointer. Note that if 'rhs' is in an empty state, this weak pointer // will be set to an empty state. weak_ptr& operator=(const weak_ptr& rhs) BSLS_KEYWORD_NOEXCEPT; // Make this weak pointer refer to the same object (if any) as the // specified 'rhs' weak pointer. Decrement the number of weak // references to the object this weak pointer manages (if any), and // increment the number of weak references to the object managed by // 'rhs' (if any). Return a reference providing modifiable access to // this weak pointer. Note that if 'rhs' is in an empty state, this // weak pointer will be set to an empty state. #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr&>::type operator=(weak_ptr<COMPATIBLE_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT; #else template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr&>::type operator=(BloombergLP::bslmf::MovableRef<weak_ptr<COMPATIBLE_TYPE> > rhs) BSLS_KEYWORD_NOEXCEPT; #endif // Make this weak pointer refer to the same object (if any) as the // specified 'rhs' weak pointer. Decrement the number of weak // references to the object this weak pointer managed (if any), and // reset 'rhs' to an empty state. Return a reference providing // modifiable access to this weak pointer. This function does not // exist unless a pointer to (the template parameter) 'COMPATIBLE_TYPE' // is convertible to a pointer to (the template parameter) // 'ELEMENT_TYPE'. Note that if 'rhs' is in an empty state, this weak // pointer will be set to an empty state. template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr&>::type operator=(const shared_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr&>::type operator=(const weak_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT; // Make this weak pointer refer to the same object (if any) as the // specified 'rhs' (shared or weak) pointer to the (template parameter) // 'COMPATIBLE_TYPE'. Decrement the number of weak references to the // object to which this weak pointer currently manages (if any), and // increment the number of weak references to the object managed by // 'rhs' (if any). Return a reference providing modifiable access to // this weak pointer. If 'COMPATIBLE_TYPE *' is not implicitly // convertible to 'TYPE *', then a compiler diagnostic will be emitted. // Note that if 'rhs' is in the empty state, this weak pointer will be // set to the empty state. void reset() BSLS_KEYWORD_NOEXCEPT; // Reset this weak pointer to the empty state. If this weak pointer // manages a (possibly shared) object, then decrement the number of // weak references to that object. void swap(weak_ptr& other) BSLS_KEYWORD_NOEXCEPT; // Efficiently exchange the states of this weak pointer and the // specified 'other' weak pointer such that each will refer to the // object (if any) and representation (if any) formerly referred to and // managed by the other. // ACCESSORS bool expired() const BSLS_KEYWORD_NOEXCEPT; // Return 'true' if this weak pointer is in the empty state or the // object that it originally referenced has been destroyed, and 'false' // otherwise. shared_ptr<ELEMENT_TYPE> lock() const BSLS_KEYWORD_NOEXCEPT; // Return a shared pointer to the object referred to by this weak // pointer if 'false == expired()', and a shared pointer in the empty // state otherwise. template <class ANY_TYPE> bool owner_before(const shared_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT; template <class ANY_TYPE> bool owner_before(const weak_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT; // Return 'true' if the address of the // 'BloombergLP::bslma::SharedPtrRep' object used by this weak pointer // is ordered before the address of the // 'BloombergLP::bslma::SharedPtrRep' object used by the specified // 'other' shared pointer under the total ordering defined by // 'std::less<BloombergLP::bslma::SharedPtrRep *>', and 'false' // otherwise. BloombergLP::bslma::SharedPtrRep *rep() const BSLS_KEYWORD_NOEXCEPT; // Return the address providing modifiable access to the // 'BloombergLP::bslma::SharedPtrRep' object held by this weak pointer, // or 0 if this weak pointer is in the empty state. long use_count() const BSLS_KEYWORD_NOEXCEPT; // Return a "snapshot" of the current number of shared pointers that // share ownership of the object referred to by this weak pointer, or 0 // if this weak pointer is in the empty state. Note that any result // other than 0 may be unreliable in a multi-threaded program, where // another pointer sharing ownership in a different thread may be // copied or destroyed, or another weak pointer may be locked in the // case that 1 is returned (that would otherwise indicate unique // ownership). #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY ACCESSORS shared_ptr<ELEMENT_TYPE> acquireSharedPtr() const BSLS_KEYWORD_NOEXCEPT; // Return a shared pointer to the object referred to by this weak // pointer and managing the same object as that managed by this weak // pointer (if any) if 'false == expired()', and a shared pointer in // the empty state otherwise. Note that the behavior of this method is // the same as that of 'lock'. int numReferences() const BSLS_KEYWORD_NOEXCEPT; // [!DEPRECATED!] Use 'use_count' instead. // // Return a "snapshot" of the current number of shared pointers that // share ownership of the object referred to by this weak pointer, or 0 // if this weak pointer is in the empty state. Note that the behavior // of this method is the same as that of 'use_count', and the result // may be unreliable in multi-threaded code for the same reasons. #endif // BDE_OMIT_INTERNAL_DEPRECATED }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD // CLASS TEMPLATE DEDUCTION GUIDES template<class ELEMENT_TYPE> weak_ptr(shared_ptr<ELEMENT_TYPE>) -> weak_ptr<ELEMENT_TYPE>; // Deduce the specified type 'ELEMENT_TYPE' corresponding template // parameter of the 'bsl::shared_ptr' supplied to the constructor of // 'weak_ptr'. #endif //============================== // class enable_shared_from_this //============================== template<class ELEMENT_TYPE> class enable_shared_from_this { // This class allows an object that is currently managed by a 'shared_ptr' // to safely generate a copy of the managing 'shared_ptr' object. // Inheriting from 'enable_shared_from_this<ELEMENT_TYPE>' provides the // (template parameter) 'ELEMENT_TYPE' type with a member function // 'shared_from_this'. If an object of type 'ELEMENT_TYPE' is managed by a // 'shared_ptr' then calling 'shared_from_this' will return a // 'shared_ptr<ELEMENT_TYPE>' that shares ownership of that object. It is // undefined behavior to call 'shared_from_this' on an object unless that // object is managed by a 'shared_ptr'. // // The intended use of 'enable_shared_from_this' is that the (template // parameter) type 'ELEMENT_TYPE' inherits directly from the // 'enable_shared_from_this' class template. In the case of multiple // inheritance, only one of the base classes should inherit from the // 'enable_shared_from_this' class template. If multiple base classes // inherit from 'enable_shared_from_this', then there will be ambiguous // calls to the 'shared_from_this' function. // FRIENDS friend struct BloombergLP::bslstl::SharedPtr_ImpUtil; // Allows 'shared_ptr' to initialize 'd_weakThis' when it detects an // 'enable_shared_from_this' base class. private: // DATA mutable bsl::weak_ptr<ELEMENT_TYPE> d_weakThis; protected: // PROTECTED CREATORS enable_shared_from_this() BSLS_KEYWORD_NOEXCEPT; // Create an 'enable_shared_from_this' object that is not owned by any // 'shared_ptr' object. enable_shared_from_this(const enable_shared_from_this& unused) BSLS_KEYWORD_NOEXCEPT; // Create an 'enable_shared_from_this' object that is not owned by any // 'shared_ptr' object. Note that the specified 'unused' argument is // not used by this constructor. ~enable_shared_from_this(); // Destroy this 'enable_shared_form_this'. // PROTECTED MANIPULATORS enable_shared_from_this& operator=(const enable_shared_from_this& rhs) BSLS_KEYWORD_NOEXCEPT; // Return '*this'. This object is unchanged. Note that the specified // 'rhs' is not used. public: // MANIPULATORS bsl::shared_ptr<ELEMENT_TYPE> shared_from_this(); // Return a 'shared_ptr<ELEMENT_TYPE>' that shares ownership with an // existing 'shared_ptr' object that managed this object, and throw a // 'std::bad_weak_ptr' exception if there is no 'shared_ptr' currently // managing this object. If multiple groups of 'shared_ptr's are // managing this object, the returned 'shared_ptr' will share ownership // with the group that first managed this object. bsl::weak_ptr<ELEMENT_TYPE> weak_from_this() BSLS_KEYWORD_NOEXCEPT; // Return a 'weak_ptr' holding a weak reference to this managed object // if this object is currently managed by 'shared_ptr', and return an // expired 'weak_ptr' otherwise. If multiple groups of 'shared_ptr's // are managing this object, the returned 'weak_ptr' will hold a weak // reference to the group that first managed this object. // ACCESSORS bsl::shared_ptr<const ELEMENT_TYPE> shared_from_this() const; // Return a 'shared_ptr<const ELEMENT_TYPE>' that shares ownership with // an existing 'shared_ptr' object that managed this object, and throw // a 'std::bad_weak_ptr' exception if there is no 'shared_ptr' // currently managing this object. If multiple groups of 'shared_ptr's // are managing this object, the returned 'shared_ptr' will share // ownership with the group that first managed this object. bsl::weak_ptr<const ELEMENT_TYPE> weak_from_this() const BSLS_KEYWORD_NOEXCEPT; // Return a 'weak_ptr' holding a weak reference (with only 'const' // access) to this managed object if this object is currently managed // by 'shared_ptr', and return an expired 'weak_ptr' otherwise. If // multiple groups of 'shared_ptr's are managing this object, the // returned 'weak_ptr' will hold a weak reference to the group that // first managed this object. }; // ASPECTS template <class ELEMENT_TYPE> void swap(weak_ptr<ELEMENT_TYPE>& a, weak_ptr<ELEMENT_TYPE>& b) BSLS_KEYWORD_NOEXCEPT; // Efficiently exchange the states of the specified 'a' and 'b' weak // pointers such that each will refer to the object (if any) and // representation formerly referred to by the other. // ========================= // class hash specialization // ========================= // A partial specialization of 'bsl::hash' is no longer necessary, as the // primary template has the correct behavior once 'hashAppend' is defined. } // close namespace bsl namespace BloombergLP { namespace bslstl { // ==================== // struct SharedPtrUtil // ==================== struct SharedPtrUtil { // This 'struct' provides a namespace for operations on shared pointers. // CLASS METHODS static bsl::shared_ptr<char> createInplaceUninitializedBuffer(size_t bufferSize, bslma::Allocator *basicAllocator = 0); // Return a shared pointer with an in-place representation holding a // newly-created uninitialized buffer of the specified 'bufferSize' (in // bytes). Optionally specify a 'basicAllocator' used to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. The behavior is undefined unless // '0 < bufferSize'. // CASTING FUNCTIONS template <class TARGET, class SOURCE> static void constCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source); // Load into the specified 'target' an aliased shared pointer sharing // ownership of the object managed by the specified 'source' shared // pointer and referring to 'const_cast<TARGET *>(source.get())'. If // '*target' is already managing a (possibly shared) object, then // release the shared reference to that object, and destroy it using // its associated deleter if that shared pointer held the last shared // reference to that object. Note that a compiler diagnostic will be // emitted indicating an error unless // 'const_cast<TARGET *>(source.get())' is a valid expression. template <class TARGET, class SOURCE> static bsl::shared_ptr<TARGET> constCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'bsl::shared_ptr<TARGET>' object sharing ownership of the // same object as the specified 'source' shared pointer to the // (template parameter) 'SOURCE' type, and referring to // 'const_cast<TARGET *>(source.get())'. Note that a compiler // diagnostic will be emitted indicating an error unless // 'const_cast<TARGET *>(source.get())' is a valid expression. template <class TARGET, class SOURCE> static void dynamicCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source); // Load into the specified 'target' an aliased shared pointer sharing // ownership of the object managed by the specified 'source' shared // pointer and referring to 'dynamic_cast<TARGET *>(source.get())'. If // '*target' is already managing a (possibly shared) object, then // release the shared reference to that object, and destroy it using // its associated deleter if that shared pointer held the last shared // reference to that object. If // '0 == dynamic_cast<TARGET*>(source.get())', then '*target' shall be // reset to an empty state that does not refer to an object. Note that // a compiler diagnostic will be emitted indicating an error unless // 'dynamic_cast<TARGET *>(source.get())' is a valid expression. template <class TARGET, class SOURCE> static bsl::shared_ptr<TARGET> dynamicCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'bsl::shared_ptr<TARGET>' object sharing ownership of the // same object as the specified 'source' shared pointer to the // (template parameter) 'SOURCE' type, and referring to // 'dynamic_cast<TARGET *>(source.get())'. If that would return a // shared pointer referring to nothing ('0 == get()'), then instead // return an (empty) default constructed shared pointer. Note that a // compiler diagnostic will be emitted indicating an error unless // 'dynamic_cast<TARGET *>(source.get())' is a valid expression.. template <class TARGET, class SOURCE> static void staticCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source); // Load into the specified 'target' an aliased shared pointer sharing // ownership of the object managed by the specified 'source' shared // pointer and referring to 'static_cast<TARGET *>(source.get())'. If // '*target' is already managing a (possibly shared) object, then // release the shared reference to that object, and destroy it using // its associated deleter if that shared pointer held the last shared // reference to that object. Note that a compiler diagnostic will be // emitted indicating an error unless // 'static_cast<TARGET *>(source.get())' is a valid expression. template <class TARGET, class SOURCE> static bsl::shared_ptr<TARGET> staticCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT; // Return a 'bsl::shared_ptr<TARGET>' object sharing ownership of the // same object as the specified 'source' shared pointer to the // (template parameter) 'SOURCE' type, and referring to // 'static_cast<TARGET *>(source.get())'. Note that a compiler // diagnostic will be emitted indicating an error unless // 'static_cast<TARGET *>(source.get())' is a valid expression. }; // ========================== // struct SharedPtrNilDeleter // ========================== struct SharedPtrNilDeleter { // This 'struct' provides a function-like shared pointer deleter that does // nothing when invoked. // ACCESSORS void operator()(const volatile void *) const BSLS_KEYWORD_NOEXCEPT; // No-Op. }; // =============================== // struct SharedPtr_DefaultDeleter // =============================== template <bool> struct SharedPtr_DefaultDeleter { // This 'struct' provides a function-like shared pointer deleter that // invokes 'delete' with the passed pointer. If the template parameter is // 'true', then the pointer is deleted using 'operator delete []'. // Otherwise, it is deleted using 'operator delete'. // ACCESSORS template <class ANY_TYPE> void operator()(ANY_TYPE *ptr) const BSLS_KEYWORD_NOEXCEPT; // Call 'delete' with the specified 'ptr'. }; //========================= // struct SharedPtr_ImpUtil //========================= struct SharedPtr_ImpUtil { // This 'struct' should be used by only 'shared_ptr' constructors. Its // purpose is to enable 'shared_ptr' constructors to determine if the // (template parameter) types 'COMPATIBLE_TYPE' or 'ELEMENT_TYPE' have a // specialization of 'enable_shared_from_this' as an unambiguous, publicly // accessible, base class. // CLASS METHODS template<class SHARED_TYPE, class ENABLE_TYPE> static void loadEnableSharedFromThis( const bsl::enable_shared_from_this<ENABLE_TYPE> *result, bsl::shared_ptr<SHARED_TYPE> *sharedPtr); // Load the specified 'result' with the control block (i.e., // 'SharedPtrRep') from the specified 'sharedPtr' if (and only if) // 'result' is not 0 and 'result' does not already refer to a // non-expired shared-pointer control block. If 'result' is 0, or if // 'result->d_weakThis' has not expired, this operation has no effect. // This operation is used to initialize data members from a type that // inherits from 'enable_shared_from_this' when constructing an // out-of-place shared pointer representation. This function shall be // called only by 'shared_ptr' constructors creating shared pointers // for classes that derive publicly and unambiguously from a // specialization of 'enabled_shared_from_this'. Note that overload // resolution will select the overload below if a supplied type does // not derive from a specialization of 'enable_shared_from_this'. static void loadEnableSharedFromThis(const volatile void *, const void *) BSLS_KEYWORD_NOEXCEPT; // Do nothing. This overload is selected, rather than the immediately // preceding template, when the 'SHARED_TYPE' template type parameter // of 'shared_ptr<SHARED_TYPE>' does not derive from a specialization // of 'enable_shared_from_this'. static void throwBadWeakPtr(); // Throw a 'bsl::bad_weak_ptr' exception. template <class TYPE> static void *voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT; // Return the specified 'address' cast as a pointer to 'void', even if // (the template parameter) 'TYPE' is cv-qualified. template <class TYPE> static TYPE *unqualify(const volatile TYPE *address) BSLS_KEYWORD_NOEXCEPT; // Return the specified 'address' of a potentially 'cv'-qualified // object of the given (template parameter) 'TYPE', cast as a pointer // to a modifiable non-volatile object of the given 'TYPE'. }; // ========================== // class SharedPtr_RepProctor // ========================== class SharedPtr_RepProctor { // This 'class' implements a proctor that, unless its 'release' method has // previously been invoked, automatically releases a reference held by the // 'bslma::SharedPtrRep' object that is supplied at construction. private: // DATA bslma::SharedPtrRep *d_rep_p; // Address of representation being managed private: // NOT IMPLEMENTED SharedPtr_RepProctor(const SharedPtr_RepProctor&); SharedPtr_RepProctor& operator=(const SharedPtr_RepProctor&); public: // CREATORS explicit SharedPtr_RepProctor(bslma::SharedPtrRep *rep) BSLS_KEYWORD_NOEXCEPT; // Create a 'SharedPtr_RepProctor' that conditionally manages the // specified 'rep' (if non-zero). ~SharedPtr_RepProctor(); // Destroy this 'SharedPtr_RepProctor', and dispose of (deallocate) the // 'bslma::SharedPtrRep' it manages (if any). If no such object is // currently being managed, this method has no effect. Note that the // destructor of the 'bslma::SharedPtrRep' will not be called as the // reference count will not be decremented. // MANIPULATORS void release() BSLS_KEYWORD_NOEXCEPT; // Release from management the object currently managed by this // proctor. If no object is currently being managed, this method has // no effect. }; } // close package namespace } // close enterprise namespace // ============================================================================ // INLINE DEFINITIONS // ============================================================================ #if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) namespace BloombergLP { namespace bslstl { template <class FUNCTOR> struct SharedPtr_TestIsCallable { private: // PRIVATE TYPES typedef BloombergLP::bslmf::Util Util; struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; // The two structs 'TrueType' and 'FalseType' are guaranteed to have // distinct sizes, so that a 'sizeof(expression)' query, where 'expression' // returns one of these two types, will give different answers depending on // which type is returned. public: // CLASS METHODS template <class ARG> static FalseType test(...); template <class ARG> static TrueType test(typename bsl::enable_if<static_cast<bool>( sizeof(BSLSTL_SHAREDPTR_SFINAE_DISCARD( Util::declval<FUNCTOR>()(Util::declval<ARG>())), 0))>::type *); // This function is never defined. It provides a property-checker that // an entity of (template parameter) type 'FACTORY' can be called like // a function with a single argument, which is a pointer to an object // of (template parameter) type 'ARG'. The 'sizeof' expression // provides an unevaluated context to check the validity of the // enclosed expression, and the ', 0' ensures that the 'sizeof' check // remains valid, even if the expression returns 'void'. Similarly, // the cast to 'void' ensures that there are no surprises with types // that overload the comma operator. Note that the cast to 'void' is // elided for Clang compilers using versions of LLVM prior to 12, which // fail to evaluate the trait properly. }; #if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1920 // Microsoft needs a workaround to correctly handle calling through function // pointers with incompatible types in Visual Studio 2017. In Visual Studio // 2019 the workaround isn't needed and crashes the compiler if enabled! // (Visual Studio versions prior to 2017 appear to not need the workaround, // based on further testing, but it's being left in place so as not to alter // this code for people using older compiler versions.) template <class RESULT, class PARAM> struct SharedPtr_TestIsCallable<RESULT(PARAM)> { private: // PRIVATE TYPES typedef BloombergLP::bslmf::Util Util; struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; // PRIVATE CLASS METHODS static RESULT callMe(PARAM); public: // CLASS METHODS template <class ARG> static FalseType test(...); template <class ARG> static TrueType test(typename bsl::enable_if<(bool)sizeof( ((void)callMe(Util::declval<ARG>())), 0 )>::type *); // This function is never defined. It provides a property-checker that // an entity of (template parameter) type 'FACTORY' can be called like // a function with a single argument, which is a pointer to an object // of (template parameter) type 'ARG'. The 'sizeof' expression // provides an unevaluated context to check the validity of the // enclosed expression, and the ', 0' ensures that the 'sizeof' check // remains valid, even if the expression returns 'void'. Similarly, // the cast to 'void' ensures that there are no surprises with types // that overload the comma operator. }; template <class RESULT, class PARAM> struct SharedPtr_TestIsCallable<RESULT(*)(PARAM)> : SharedPtr_TestIsCallable<RESULT(PARAM)> { }; template <class RESULT, class PARAM> struct SharedPtr_TestIsCallable<RESULT(&)(PARAM)> : SharedPtr_TestIsCallable<RESULT(PARAM)> { }; #if BSLS_PLATFORM_CMP_VERSION >= 1910 // MSVC 2017 expression-SFINAE has a regression that is failing in two // additional cases: // 1) for pointers to object types // 2) where '0' is used for a null pointer literal, deducing as 'int'. // We resolve those issues with a couple more specializations below. template <class TYPE> struct SharedPtr_TestIsCallable<TYPE *> { struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; template <class ARG> static FalseType test(...); }; template <> struct SharedPtr_TestIsCallable<int> { struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; template <class ARG> static FalseType test(...); }; #endif // MSVC 2017 #endif // BSLS_PLATFORM_CMP_MSVC template <class FUNCTOR, class ARG> struct SharedPtr_IsCallable { enum { k_VALUE = sizeof(SharedPtr_TestIsCallable<FUNCTOR>::template test<ARG>(0)) == 1 }; }; struct SharedPtr_IsFactoryFor_Impl { private: // PRIVATE TYPES struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; public: // CLASS METHODS template <class FACTORY, class ARG> static FalseType test(...); template <class FACTORY, class ARG> static TrueType test(typename bsl::enable_if<static_cast<bool>(sizeof( BSLSTL_SHAREDPTR_SFINAE_DISCARD( (*(FACTORY *)0)->deleteObject((ARG *)0)), 0))>::type *); // This function is never defined. It provides a property-checker that // an object of (template parameter) type 'FACTORY' has a // member-function called 'deleteObject' that can be called with a // single argument, which is a pointer to an object of (template // parameter) type 'ARG'. The 'sizeof' expression provides an // unevaluated context to check the validity of the enclosed // expression, and the ', 0' ensures that the 'sizeof' check remains // valid, even if the expression returns 'void'. Similarly, the cast // to 'void' ensures that there are no surprises with types that // overload the comma operator. Note that the cast to 'void' is elided // for Clang compilers using versions of LLVM prior to 12, which fail // to evaluate the trait properly. }; template <class FACTORY, class ARG> struct SharedPtr_IsFactoryFor { enum { k_VALUE = sizeof(SharedPtr_IsFactoryFor_Impl::test<FACTORY, ARG>(0)) == 1 }; }; struct SharedPtr_IsNullableFactory_Impl { private: // PRIVATE TYPES struct TrueType { char d_padding; }; struct FalseType { char d_padding[17]; }; public: // CLASS METHODS template <class FACTORY> static FalseType test(...); template <class FACTORY> static TrueType test(typename bsl::enable_if<static_cast<bool>(sizeof( BSLSTL_SHAREDPTR_SFINAE_DISCARD( (*(FACTORY *)0)->deleteObject(nullptr)), 0))>::type *); // This function is never defined. It provides a property-checker that // an object of (template parameter) type 'FACTORY' has a // member-function called 'deleteObject' that can be called with a // single argument, which is a pointer to an object of (template // parameter) type 'ARG'. The 'sizeof' expression provides an // unevaluated context to check the validity of the enclosed // expression, and the ', 0' ensures that the 'sizeof' check remains // valid, even if the expression returns 'void'. Similarly, the cast // to 'void' ensures that there are no surprises with types that // overload the comma operator. Note that the cast to 'void' is elided // for Clang compilers using versions of LLVM prior to 12, which fail // to evaluate the trait properly. }; template <class FACTORY> struct SharedPtr_IsNullableFactory { enum { k_VALUE = sizeof(SharedPtr_IsNullableFactory_Impl::test<FACTORY>(0)) == 1 }; }; template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerConvertible_Impl : bsl::is_convertible<SOURCE_TYPE *, DEST_TYPE *>::type {}; template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerConvertible_Impl<SOURCE_TYPE, DEST_TYPE[]> : bsl::is_convertible<SOURCE_TYPE (*)[], DEST_TYPE (*)[]>::type {}; template <class SOURCE_TYPE, class DEST_TYPE, size_t DEST_SIZE> struct SharedPtr_IsPointerConvertible_Impl<SOURCE_TYPE, DEST_TYPE[DEST_SIZE]> : bsl::is_convertible<SOURCE_TYPE (*)[DEST_SIZE], DEST_TYPE (*)[DEST_SIZE]>::type {}; template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerConvertible : SharedPtr_IsPointerConvertible_Impl<SOURCE_TYPE, DEST_TYPE>::type {}; template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerCompatible_Impl : bsl::is_convertible<SOURCE_TYPE *, DEST_TYPE *>::type {}; template <class TYPE, size_t SIZE> struct SharedPtr_IsPointerCompatible_Impl<TYPE[SIZE], TYPE[]> : bsl::true_type {}; template <class TYPE, size_t SIZE> struct SharedPtr_IsPointerCompatible_Impl<TYPE[SIZE], const TYPE[]> : bsl::true_type {}; template <class TYPE, size_t SIZE> struct SharedPtr_IsPointerCompatible_Impl<TYPE[SIZE], volatile TYPE[]> : bsl::true_type {}; template <class TYPE, size_t SIZE> struct SharedPtr_IsPointerCompatible_Impl<TYPE[SIZE], const volatile TYPE[]> : bsl::true_type {}; template <class SOURCE_TYPE, class DEST_TYPE> struct SharedPtr_IsPointerCompatible : SharedPtr_IsPointerCompatible_Impl<SOURCE_TYPE, DEST_TYPE>::type {}; } // close package namespace } // close enterprise namespace #endif // BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS namespace bsl { //------------------------------ // class enable_shared_from_this //------------------------------ // CREATORS template<class ELEMENT_TYPE> inline // constexpr enable_shared_from_this<ELEMENT_TYPE>::enable_shared_from_this() BSLS_KEYWORD_NOEXCEPT : d_weakThis() { } template<class ELEMENT_TYPE> inline enable_shared_from_this<ELEMENT_TYPE>::enable_shared_from_this( const enable_shared_from_this&) BSLS_KEYWORD_NOEXCEPT : d_weakThis() { } template<class ELEMENT_TYPE> inline enable_shared_from_this<ELEMENT_TYPE>::~enable_shared_from_this() { } // MANIPULATORS template<class ELEMENT_TYPE> inline enable_shared_from_this<ELEMENT_TYPE>& enable_shared_from_this<ELEMENT_TYPE>::operator=( const enable_shared_from_this&) BSLS_KEYWORD_NOEXCEPT { return *this; } template<class ELEMENT_TYPE> inline shared_ptr<ELEMENT_TYPE> enable_shared_from_this<ELEMENT_TYPE>::shared_from_this() { return shared_ptr<ELEMENT_TYPE>(d_weakThis); } template<class ELEMENT_TYPE> inline shared_ptr<const ELEMENT_TYPE> enable_shared_from_this<ELEMENT_TYPE>::shared_from_this() const { return shared_ptr<const ELEMENT_TYPE>(d_weakThis); } template<class ELEMENT_TYPE> inline weak_ptr<ELEMENT_TYPE> enable_shared_from_this<ELEMENT_TYPE>::weak_from_this() BSLS_KEYWORD_NOEXCEPT { return d_weakThis; } template<class ELEMENT_TYPE> inline weak_ptr<const ELEMENT_TYPE> enable_shared_from_this<ELEMENT_TYPE>::weak_from_this() const BSLS_KEYWORD_NOEXCEPT { return d_weakThis; } // ---------------- // class shared_ptr // ---------------- // PRIVATE CLASS METHODS template <class ELEMENT_TYPE> template <class INPLACE_REP> inline BloombergLP::bslma::SharedPtrRep * shared_ptr<ELEMENT_TYPE>::makeInternalRep( ELEMENT_TYPE *, INPLACE_REP *, BloombergLP::bslma::SharedPtrRep *rep) { return rep; } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class ALLOCATOR> inline BloombergLP::bslma::SharedPtrRep * shared_ptr<ELEMENT_TYPE>::makeInternalRep( COMPATIBLE_TYPE *ptr, ALLOCATOR *, BloombergLP::bslma::Allocator *allocator) { typedef BloombergLP::bslma::SharedPtrOutofplaceRep< COMPATIBLE_TYPE, BloombergLP::bslma::Allocator *> RepMaker; return RepMaker::makeOutofplaceRep(ptr, allocator, allocator); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class DELETER> inline BloombergLP::bslma::SharedPtrRep * shared_ptr<ELEMENT_TYPE>::makeInternalRep(COMPATIBLE_TYPE *ptr, DELETER *deleter, ...) { typedef BloombergLP::bslma::SharedPtrOutofplaceRep<COMPATIBLE_TYPE, DELETER *> RepMaker; return RepMaker::makeOutofplaceRep(ptr, deleter, 0); } // CREATORS template <class ELEMENT_TYPE> inline BSLS_KEYWORD_CONSTEXPR shared_ptr<ELEMENT_TYPE>::shared_ptr() BSLS_KEYWORD_NOEXCEPT : d_ptr_p(0) , d_rep_p(0) { } template <class ELEMENT_TYPE> inline BSLS_KEYWORD_CONSTEXPR shared_ptr<ELEMENT_TYPE>::shared_ptr(bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(0) , d_rep_p(0) { } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE> inline shared_ptr<ELEMENT_TYPE>::shared_ptr(CONVERTIBLE_TYPE *ptr) : d_ptr_p(ptr) { typedef BloombergLP::bslstl::SharedPtr_DefaultDeleter< bsl::is_array<ELEMENT_TYPE>::value> Deleter; typedef BloombergLP::bslma::SharedPtrOutofplaceRep<CONVERTIBLE_TYPE, Deleter> RepMaker; d_rep_p = RepMaker::makeOutofplaceRep(ptr, Deleter(), 0); if (!bsl::is_array<ELEMENT_TYPE>::value) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE> inline shared_ptr<ELEMENT_TYPE>::shared_ptr( CONVERTIBLE_TYPE *ptr, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(ptr) { typedef BloombergLP::bslma::SharedPtrOutofplaceRep< CONVERTIBLE_TYPE, BloombergLP::bslma::Allocator *> RepMaker; d_rep_p = RepMaker::makeOutofplaceRep(ptr, basicAllocator, basicAllocator); if (!bsl::is_array<ELEMENT_TYPE>::value) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } } template <class ELEMENT_TYPE> inline shared_ptr<ELEMENT_TYPE>::shared_ptr(ELEMENT_TYPE *ptr, BloombergLP::bslma::SharedPtrRep *rep) : d_ptr_p(ptr) , d_rep_p(rep) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } template <class ELEMENT_TYPE> inline shared_ptr<ELEMENT_TYPE>::shared_ptr( ELEMENT_TYPE *ptr, BloombergLP::bslma::SharedPtrRep *rep, BloombergLP::bslstl::SharedPtr_RepFromExistingSharedPtr) : d_ptr_p(ptr) , d_rep_p(rep) { } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE, class DISPATCH BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DEFINE_IF_DELETER(DISPATCH *, CONVERTIBLE_TYPE)> inline shared_ptr<ELEMENT_TYPE>::shared_ptr(CONVERTIBLE_TYPE *ptr, DISPATCH *dispatch) : d_ptr_p(ptr) , d_rep_p(makeInternalRep(ptr, dispatch, dispatch)) { if (!bsl::is_array<ELEMENT_TYPE>::value) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE, class DELETER BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DEFINE_IF_DELETER(DELETER, CONVERTIBLE_TYPE)> inline shared_ptr<ELEMENT_TYPE>::shared_ptr( CONVERTIBLE_TYPE *ptr, DELETER deleter, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(ptr) { typedef BloombergLP::bslma::SharedPtrOutofplaceRep<CONVERTIBLE_TYPE, DELETER> RepMaker; d_rep_p = RepMaker::makeOutofplaceRep(ptr, deleter, basicAllocator); if (!bsl::is_array<ELEMENT_TYPE>::value) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE, class DELETER, class ALLOCATOR BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE BSLSTL_SHAREDPTR_DEFINE_IF_DELETER(DELETER, CONVERTIBLE_TYPE)> inline shared_ptr<ELEMENT_TYPE>::shared_ptr(CONVERTIBLE_TYPE *ptr, DELETER deleter, ALLOCATOR basicAllocator, typename ALLOCATOR::value_type *) : d_ptr_p(ptr) { #ifdef BSLS_PLATFORM_CMP_MSVC // This is not quite C++11 'decay' as we do not need to worry about array // types, and do not want to remove reference or cv-qualification from // DELETER otherwise. This works around a Microsoft bug turning function // pointers into function references. typedef typename bsl::conditional<bsl::is_function<DELETER>::value, typename bsl::add_pointer<DELETER>::type, DELETER>::type DeleterType; #else typedef DELETER DeleterType; #endif typedef BloombergLP::bslstl::SharedPtrAllocateOutofplaceRep<CONVERTIBLE_TYPE, DeleterType, ALLOCATOR> RepMaker; d_rep_p = RepMaker::makeOutofplaceRep(ptr, deleter, basicAllocator); if (!bsl::is_array<ELEMENT_TYPE>::value) { BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(ptr, this); } } template <class ELEMENT_TYPE> inline shared_ptr<ELEMENT_TYPE>::shared_ptr(nullptr_t, BloombergLP::bslma::Allocator *) : d_ptr_p(0) , d_rep_p(0) { } template <class ELEMENT_TYPE> template <class DELETER BSLSTL_SHAREDPTR_DEFINE_IF_NULLPTR_DELETER(DELETER)> inline shared_ptr<ELEMENT_TYPE>::shared_ptr( nullptr_t, DELETER deleter, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(0) { typedef BloombergLP::bslma::SharedPtrOutofplaceRep<ELEMENT_TYPE, DELETER> RepMaker; if (bsl::is_convertible<DELETER, BloombergLP::bslma::Allocator *>::value && bsl::is_pointer<DELETER>::value) { d_rep_p = 0; } else { d_rep_p = RepMaker::makeOutofplaceRep((ELEMENT_TYPE *)0, deleter, basicAllocator); } } template <class ELEMENT_TYPE> template <class DELETER, class ALLOCATOR BSLSTL_SHAREDPTR_DEFINE_IF_NULLPTR_DELETER(DELETER)> inline shared_ptr<ELEMENT_TYPE>::shared_ptr( nullptr_t, DELETER deleter, ALLOCATOR basicAllocator, typename ALLOCATOR::value_type *) : d_ptr_p(0) { #ifdef BSLS_PLATFORM_CMP_MSVC // This is not quite C++11 'decay' as we do not need to worry about array // types, and do not want to remove reference or cv-qualification from // DELETER otherwise. This works around a Microsoft bug turning function // pointers into function references. typedef typename bsl::conditional<bsl::is_function<DELETER>::value, typename bsl::add_pointer<DELETER>::type, DELETER>::type DeleterType; #else typedef DELETER DeleterType; #endif typedef BloombergLP::bslstl::SharedPtrAllocateOutofplaceRep<ELEMENT_TYPE, DeleterType, ALLOCATOR> RepMaker; d_rep_p = RepMaker::makeOutofplaceRep((ELEMENT_TYPE *)0, deleter, basicAllocator); } template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE> shared_ptr<ELEMENT_TYPE>::shared_ptr( BloombergLP::bslma::ManagedPtr<CONVERTIBLE_TYPE> managedPtr, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(managedPtr.ptr()) , d_rep_p(0) { typedef BloombergLP::bslma::SharedPtrInplaceRep< BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE> > Rep; if (d_ptr_p) { ELEMENT_TYPE *pPotentiallyShared = static_cast<ELEMENT_TYPE *>( managedPtr.deleter().object()); if (&BloombergLP::bslma::SharedPtrRep::managedPtrDeleter == managedPtr.deleter().deleter()) { d_rep_p = static_cast<BloombergLP::bslma::SharedPtrRep *> (managedPtr.release().second.factory()); } else if (&BloombergLP::bslma::SharedPtrRep::managedPtrEmptyDeleter == managedPtr.deleter().deleter()) { d_rep_p = 0; managedPtr.release(); } else { basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator); (*rep->ptr()) = managedPtr; d_rep_p = rep; } BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis( pPotentiallyShared, this); } } #if defined(BSLS_LIBRARYFEATURES_HAS_CPP98_AUTO_PTR) template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE> shared_ptr<ELEMENT_TYPE>::shared_ptr( std::auto_ptr<CONVERTIBLE_TYPE>& autoPtr, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(autoPtr.get()) , d_rep_p(0) { typedef BloombergLP::bslma::SharedPtrInplaceRep< std::auto_ptr<CONVERTIBLE_TYPE> > Rep; if (d_ptr_p) { basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator); (*rep->ptr()) = autoPtr; d_rep_p = rep; BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis( d_ptr_p, this); } } template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>::shared_ptr( std::auto_ptr_ref<ELEMENT_TYPE> autoRef, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(0) , d_rep_p(0) { typedef BloombergLP::bslma::SharedPtrInplaceRep< std::auto_ptr<ELEMENT_TYPE> > Rep; std::auto_ptr<ELEMENT_TYPE> autoPtr(autoRef); if (autoPtr.get()) { basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator); d_ptr_p = autoPtr.get(); (*rep->ptr()) = autoPtr; d_rep_p = rep; } } #endif #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_UNIQUE_PTR) # if defined(BSLSTL_SHAREDPTR_SUPPORTS_SFINAE_CHECKS) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class UNIQUE_DELETER, typename enable_if<is_convertible< typename std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>::pointer, ELEMENT_TYPE *>::value>::type *> shared_ptr<ELEMENT_TYPE>::shared_ptr( std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>&& adoptee, BloombergLP::bslma::Allocator *basicAllocator) : d_ptr_p(adoptee.get()) , d_rep_p(0) { typedef BloombergLP::bslma::SharedPtrInplaceRep< std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER> > Rep; if (d_ptr_p) { basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator, BloombergLP::bslmf::MovableRefUtil::move(adoptee)); d_rep_p = rep; BloombergLP::bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis( d_ptr_p, this); } } # endif #endif template <class ELEMENT_TYPE> template <class ANY_TYPE> shared_ptr<ELEMENT_TYPE>::shared_ptr(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *object) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(object) , d_rep_p(source.d_rep_p) { if (d_rep_p) { d_rep_p->acquireRef(); } } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> shared_ptr<ELEMENT_TYPE>:: shared_ptr(const shared_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(other.d_ptr_p) , d_rep_p(other.d_rep_p) { if (d_rep_p) { d_rep_p->acquireRef(); } } template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>::shared_ptr(const shared_ptr& original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(original.d_ptr_p) , d_rep_p(original.d_rep_p) { if (d_rep_p) { d_rep_p->acquireRef(); } } template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>::shared_ptr (BloombergLP::bslmf::MovableRef<shared_ptr> original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(BloombergLP::bslmf::MovableRefUtil::access(original).d_ptr_p) , d_rep_p(BloombergLP::bslmf::MovableRefUtil::access(original).d_rep_p) { BloombergLP::bslmf::MovableRefUtil::access(original).d_ptr_p = 0; BloombergLP::bslmf::MovableRefUtil::access(original).d_rep_p = 0; } #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> shared_ptr<ELEMENT_TYPE>::shared_ptr(shared_ptr<COMPATIBLE_TYPE>&& other) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(other.d_ptr_p) , d_rep_p(other.d_rep_p) { other.d_ptr_p = 0; other.d_rep_p = 0; } #else template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> shared_ptr<ELEMENT_TYPE>:: shared_ptr(BloombergLP::bslmf::MovableRef<shared_ptr<COMPATIBLE_TYPE> > other) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(BloombergLP::bslmf::MovableRefUtil::access(other).d_ptr_p) , d_rep_p(BloombergLP::bslmf::MovableRefUtil::access(other).d_rep_p) { BloombergLP::bslmf::MovableRefUtil::access(other).d_ptr_p = 0; BloombergLP::bslmf::MovableRefUtil::access(other).d_rep_p = 0; } #endif template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> shared_ptr<ELEMENT_TYPE>::shared_ptr(const weak_ptr<COMPATIBLE_TYPE>& other) : d_ptr_p(0) , d_rep_p(0) { // This implementation handles two awkward cases: // // i) a ref-counted null pointer, means we cannot simply test 'if (!value)' // ii) a null pointer aliasing a non-null pointer is still expired, and so // should throw. SelfType value = other.lock(); if (other.expired()) { // Test after lock to avoid a race between testing 'expired' and // claiming the lock. BloombergLP::bslstl::SharedPtr_ImpUtil::throwBadWeakPtr(); } swap(value); } #if !defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> shared_ptr<ELEMENT_TYPE>::shared_ptr( BloombergLP::bslmf::MovableRef<weak_ptr<COMPATIBLE_TYPE> > ptr) : d_ptr_p(0) , d_rep_p(0) { // This implementation handles two awkward cases: // // i) a ref-counted null pointer, means we cannot simply test 'if (!value)' // ii) a null pointer aliasing a non-null pointer is still expired, and so // should throw. weak_ptr<COMPATIBLE_TYPE>& other = ptr; SelfType value = other.lock(); if (other.expired()) { // Test after lock to avoid a race between testing 'expired' and // claiming the lock. BloombergLP::bslstl::SharedPtr_ImpUtil::throwBadWeakPtr(); } swap(value); } #endif template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>::~shared_ptr() { if (d_rep_p) { d_rep_p->releaseRef(); } } // MANIPULATORS template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>& shared_ptr<ELEMENT_TYPE>::operator=(const shared_ptr& rhs) BSLS_KEYWORD_NOEXCEPT { // Instead of testing '&rhs == this', which happens infrequently, optimize // for when reps are the same. if (rhs.d_rep_p == d_rep_p) { d_ptr_p = rhs.d_ptr_p; } else { SelfType(rhs).swap(*this); } return *this; } template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>& shared_ptr<ELEMENT_TYPE>::operator=( BloombergLP::bslmf::MovableRef<shared_ptr> rhs) BSLS_KEYWORD_NOEXCEPT { // No self-assignment to optimize, postcondition demands 'rhs' is left // empty, unless it is the exact same object, not just the same 'rep'. shared_ptr(BloombergLP::bslmf::MovableRefUtil::move(rhs)).swap(*this); return *this; } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=(const shared_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { // Instead of testing '&rhs == this', which happens infrequently, optimize // for when reps are the same. if (rhs.d_rep_p == d_rep_p) { d_ptr_p = rhs.d_ptr_p; } else { SelfType(rhs).swap(*this); } return *this; } #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=(shared_ptr<COMPATIBLE_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT #else template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=( BloombergLP::bslmf::MovableRef<shared_ptr<COMPATIBLE_TYPE> > rhs) BSLS_KEYWORD_NOEXCEPT #endif { // No self-assignment to optimize, postcondition demands 'rhs' is left // empty, unless it is the exact same object, not just the same 'rep'. shared_ptr(BloombergLP::bslmf::MovableRefUtil::move(rhs)).swap(*this); return *this; } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> inline typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=( BloombergLP::bslma::ManagedPtr<COMPATIBLE_TYPE> rhs) { SelfType(rhs).swap(*this); return *this; } #if defined(BSLS_LIBRARYFEATURES_HAS_CPP98_AUTO_PTR) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> inline typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=(std::auto_ptr<COMPATIBLE_TYPE> rhs) { SelfType(rhs).swap(*this); return *this; } #endif #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_UNIQUE_PTR) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class UNIQUE_DELETER> inline typename enable_if< is_convertible< typename std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>::pointer, ELEMENT_TYPE *>::value, shared_ptr<ELEMENT_TYPE>&>::type shared_ptr<ELEMENT_TYPE>::operator=( std::unique_ptr<COMPATIBLE_TYPE, UNIQUE_DELETER>&& rhs) { SelfType(BloombergLP::bslmf::MovableRefUtil::move(rhs)).swap(*this); return *this; } #endif template <class ELEMENT_TYPE> inline void shared_ptr<ELEMENT_TYPE>::reset() BSLS_KEYWORD_NOEXCEPT { BloombergLP::bslma::SharedPtrRep *rep = d_rep_p; // Clear 'd_rep_p' first so that a self-referencing shared pointer's // destructor does not try to call 'releaseRef' again. d_rep_p = 0; d_ptr_p = 0; if (rep) { rep->releaseRef(); } } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> inline typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type shared_ptr<ELEMENT_TYPE>::reset(COMPATIBLE_TYPE *ptr) { SelfType(ptr).swap(*this); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class DELETER> inline typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type shared_ptr<ELEMENT_TYPE>::reset(COMPATIBLE_TYPE *ptr, DELETER deleter) { SelfType(ptr, deleter).swap(*this); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class DELETER, class ALLOCATOR> inline typename enable_if<is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value>::type shared_ptr<ELEMENT_TYPE>::reset(COMPATIBLE_TYPE *ptr, DELETER deleter, ALLOCATOR basicAllocator) { SelfType(ptr, deleter, basicAllocator).swap(*this); } template <class ELEMENT_TYPE> template <class ANY_TYPE> inline void shared_ptr<ELEMENT_TYPE>::reset(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *ptr) { // Optimize for the (expected) common case where aliases are managing the // same data structure. if (source.d_rep_p == d_rep_p && ptr) { d_ptr_p = ptr; } else { SelfType(source, ptr).swap(*this); } } template <class ELEMENT_TYPE> inline void shared_ptr<ELEMENT_TYPE>::swap(shared_ptr& other) BSLS_KEYWORD_NOEXCEPT { // We directly implement swapping of two pointers, rather than simply // calling 'bsl::swap' or using 'bslalg::SwapUtil', to avoid (indirectly) // including the platform <algorithm> header, which may transitively // include other standard headers. This reduces the risk of // platform-specific cycles, which have been observed to cause problems. // Also, as 'shared_ptr' is bitwise-moveable, we could simplify this to // 'memcpy'-ing through an (aligned?) array of sufficient 'char'. ELEMENT_TYPE *tempPtr_p = d_ptr_p; d_ptr_p = other.d_ptr_p; other.d_ptr_p = tempPtr_p; BloombergLP::bslma::SharedPtrRep *tempRep_p = d_rep_p; d_rep_p = other.d_rep_p; other.d_rep_p = tempRep_p; } // ADDITIONAL BSL MANIPULATORS template<class ELEMENT_TYPE> void shared_ptr<ELEMENT_TYPE>::createInplace() { typedef BloombergLP::bslma::SharedPtrInplaceRep<ELEMENT_TYPE> Rep; BloombergLP::bslma::Allocator *basicAllocator = BloombergLP::bslma::Default::allocator(); Rep *rep = new (*basicAllocator) Rep(basicAllocator); SelfType(rep->ptr(), rep).swap(*this); } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class ELEMENT_TYPE> template <class... ARGS> void shared_ptr<ELEMENT_TYPE>::createInplace( BloombergLP::bslma::Allocator *basicAllocator, ARGS&&... args) { typedef BloombergLP::bslma::SharedPtrInplaceRep<ELEMENT_TYPE> Rep; basicAllocator = BloombergLP::bslma::Default::allocator(basicAllocator); Rep *rep = new (*basicAllocator) Rep(basicAllocator, BSLS_COMPILERFEATURES_FORWARD(ARGS,args)...); SelfType(rep->ptr(), rep).swap(*this); } #endif template <class ELEMENT_TYPE> template <class ANY_TYPE> void shared_ptr<ELEMENT_TYPE>::loadAlias(const shared_ptr<ANY_TYPE>& source, ELEMENT_TYPE *object) { if (source.d_rep_p == d_rep_p && object) { d_ptr_p = object; } else { SelfType(source, object).swap(*this); } } template <class ELEMENT_TYPE> pair<ELEMENT_TYPE *, BloombergLP::bslma::SharedPtrRep *> shared_ptr<ELEMENT_TYPE>::release() BSLS_KEYWORD_NOEXCEPT { pair<ELEMENT_TYPE *, BloombergLP::bslma::SharedPtrRep *> ret(d_ptr_p, d_rep_p); d_ptr_p = 0; d_rep_p = 0; return ret; } #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY MANIPULATORS template <class ELEMENT_TYPE> inline void shared_ptr<ELEMENT_TYPE>::clear() BSLS_KEYWORD_NOEXCEPT { reset(); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> inline void shared_ptr<ELEMENT_TYPE>::load(COMPATIBLE_TYPE *ptr) { SelfType(ptr).swap(*this); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> inline void shared_ptr<ELEMENT_TYPE>::load(COMPATIBLE_TYPE *ptr, BloombergLP::bslma::Allocator *basicAllocator) { SelfType(ptr, basicAllocator).swap(*this); } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE, class DELETER> inline void shared_ptr<ELEMENT_TYPE>::load(COMPATIBLE_TYPE *ptr, const DELETER& deleter, BloombergLP::bslma::Allocator *basicAllocator) { SelfType(ptr, deleter, basicAllocator).swap(*this); } #endif // BDE_OMIT_INTERNAL_DEPRECATED // ACCESSORS template <class ELEMENT_TYPE> inline # if defined(BSLS_PLATFORM_CMP_IBM) // Last tested with xlC 12.1 shared_ptr<ELEMENT_TYPE>::operator typename shared_ptr::BoolType() const BSLS_KEYWORD_NOEXCEPT # else shared_ptr<ELEMENT_TYPE>::operator BoolType() const BSLS_KEYWORD_NOEXCEPT # endif { return BloombergLP::bsls::UnspecifiedBool<shared_ptr>::makeValue(d_ptr_p); } template <class ELEMENT_TYPE> inline typename add_lvalue_reference<ELEMENT_TYPE>::type shared_ptr<ELEMENT_TYPE>::operator*() const BSLS_KEYWORD_NOEXCEPT { BSLS_ASSERT_SAFE(d_ptr_p); return *d_ptr_p; } template <class ELEMENT_TYPE> inline ELEMENT_TYPE *shared_ptr<ELEMENT_TYPE>::operator->() const BSLS_KEYWORD_NOEXCEPT { return d_ptr_p; } template <class ELEMENT_TYPE> inline typename shared_ptr<ELEMENT_TYPE>::element_type * shared_ptr<ELEMENT_TYPE>::get() const BSLS_KEYWORD_NOEXCEPT { return d_ptr_p; } template <class ELEMENT_TYPE> inline typename add_lvalue_reference<typename shared_ptr<ELEMENT_TYPE>::element_type>::type shared_ptr<ELEMENT_TYPE>::operator[](ptrdiff_t index) const { BSLS_ASSERT_SAFE(d_ptr_p); return *(d_ptr_p + index); } template <class ELEMENT_TYPE> template<class ANY_TYPE> inline bool shared_ptr<ELEMENT_TYPE>::owner_before(const shared_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT { return std::less<BloombergLP::bslma::SharedPtrRep *>()(rep(), other.rep()); } template <class ELEMENT_TYPE> template<class ANY_TYPE> inline bool shared_ptr<ELEMENT_TYPE>::owner_before(const weak_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT { return std::less<BloombergLP::bslma::SharedPtrRep *>()(rep(), other.rep()); } template <class ELEMENT_TYPE> inline bool shared_ptr<ELEMENT_TYPE>::unique() const BSLS_KEYWORD_NOEXCEPT { return 1 == use_count(); } template <class ELEMENT_TYPE> inline long shared_ptr<ELEMENT_TYPE>::use_count() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p ? d_rep_p->numReferences() : 0; } // ADDITIONAL BSL ACCESSORS template <class ELEMENT_TYPE> BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE>::managedPtr() const { if (d_rep_p && d_ptr_p) { d_rep_p->acquireRef(); return BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE>(d_ptr_p, d_rep_p, &BloombergLP::bslma::SharedPtrRep::managedPtrDeleter); // RETURN } return BloombergLP::bslma::ManagedPtr<ELEMENT_TYPE>( d_ptr_p, (BloombergLP::bslma::SharedPtrRep *)0, &BloombergLP::bslma::SharedPtrRep::managedPtrEmptyDeleter); } template <class ELEMENT_TYPE> inline BloombergLP::bslma::SharedPtrRep *shared_ptr<ELEMENT_TYPE>::rep() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p; } #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY ACCESSORS template <class ELEMENT_TYPE> inline int shared_ptr<ELEMENT_TYPE>::numReferences() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p ? d_rep_p->numReferences() : 0; } template <class ELEMENT_TYPE> inline ELEMENT_TYPE *shared_ptr<ELEMENT_TYPE>::ptr() const BSLS_KEYWORD_NOEXCEPT { return d_ptr_p; } #endif // BDE_OMIT_INTERNAL_DEPRECATED // -------------- // class weak_ptr // -------------- // CREATORS template <class ELEMENT_TYPE> inline BSLS_KEYWORD_CONSTEXPR weak_ptr<ELEMENT_TYPE>::weak_ptr() BSLS_KEYWORD_NOEXCEPT : d_ptr_p(0) , d_rep_p(0) { } template <class ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>::weak_ptr( BloombergLP::bslmf::MovableRef<weak_ptr> original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(BloombergLP::bslmf::MovableRefUtil::access(original).d_ptr_p) , d_rep_p(BloombergLP::bslmf::MovableRefUtil::access(original).d_rep_p) { BloombergLP::bslmf::MovableRefUtil::access(original).d_rep_p = 0; // original.d_ptr_p = 0; // this seems overkill for a /weak/ pointer } #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> weak_ptr<ELEMENT_TYPE>::weak_ptr(weak_ptr<COMPATIBLE_TYPE>&& original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(original.d_ptr_p) , d_rep_p(original.d_rep_p) { original.d_rep_p = 0; // original.d_ptr_p = 0; // this seems overkill for a /weak/ pointer } #else template <class ELEMENT_TYPE> template <class CONVERTIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE> weak_ptr<ELEMENT_TYPE>::weak_ptr( BloombergLP::bslmf::MovableRef<weak_ptr<CONVERTIBLE_TYPE> > original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(original.d_ptr_p) , d_rep_p(original.d_rep_p) { original.d_rep_p = 0; // original.d_ptr_p = 0; // this seems overkill for a /weak/ pointer } #endif template <class ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>::weak_ptr(const weak_ptr<ELEMENT_TYPE>& original) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(original.d_ptr_p) , d_rep_p(original.d_rep_p) { if (d_rep_p) { d_rep_p->acquireWeakRef(); } } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> weak_ptr<ELEMENT_TYPE>::weak_ptr(const shared_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(other.get()) , d_rep_p(other.rep()) { if (d_rep_p) { d_rep_p->acquireWeakRef(); } } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE> weak_ptr<ELEMENT_TYPE>::weak_ptr(const weak_ptr<COMPATIBLE_TYPE>& other) BSLS_KEYWORD_NOEXCEPT : d_ptr_p(other.d_ptr_p) , d_rep_p(other.d_rep_p) { if (d_rep_p) { d_rep_p->acquireWeakRef(); } } template <class ELEMENT_TYPE> inline weak_ptr<ELEMENT_TYPE>::~weak_ptr() { if (d_rep_p) { d_rep_p->releaseWeakRef(); } } // PRIVATE MANIPULATORS template <class ELEMENT_TYPE> inline void weak_ptr<ELEMENT_TYPE>::privateAssign( BloombergLP::bslma::SharedPtrRep *rep, ELEMENT_TYPE *target) { if (d_rep_p) { d_rep_p->releaseWeakRef(); } d_ptr_p = target; d_rep_p = rep; d_rep_p->acquireWeakRef(); } // MANIPULATORS template <class ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>& weak_ptr<ELEMENT_TYPE>::operator=( BloombergLP::bslmf::MovableRef<weak_ptr> rhs) BSLS_KEYWORD_NOEXCEPT { weak_ptr tmp(BloombergLP::bslmf::MovableRefUtil::move(rhs)); tmp.swap(*this); return *this; } #if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES) template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr<ELEMENT_TYPE>&>::type weak_ptr<ELEMENT_TYPE>::operator=(weak_ptr<COMPATIBLE_TYPE>&& rhs) BSLS_KEYWORD_NOEXCEPT { weak_ptr tmp(BloombergLP::bslmf::MovableRefUtil::move(rhs)); tmp.swap(*this); return *this; } #else template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr<ELEMENT_TYPE>&>::type weak_ptr<ELEMENT_TYPE>::operator=( BloombergLP::bslmf::MovableRef<weak_ptr<COMPATIBLE_TYPE> > rhs) BSLS_KEYWORD_NOEXCEPT { weak_ptr tmp(BloombergLP::bslmf::MovableRefUtil::move(rhs)); tmp.swap(*this); return *this; } #endif template <class ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>& weak_ptr<ELEMENT_TYPE>::operator=( const weak_ptr<ELEMENT_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { #if 1 weak_ptr tmp(rhs); tmp.swap(*this); #else // needs friendship, or use the cheating util class. privateAssign(rhs.d_rep_p, rhs.d_ptr_p); #endif return *this; } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr<ELEMENT_TYPE>&>::type weak_ptr<ELEMENT_TYPE>::operator=(const shared_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { #if 1 weak_ptr tmp(rhs); tmp.swap(*this); #else // needs friendship, or use the cheating util class. privateAssign(rhs.d_rep_p, rhs.d_ptr_p); #endif return *this; } template <class ELEMENT_TYPE> template <class COMPATIBLE_TYPE> typename enable_if< is_convertible<COMPATIBLE_TYPE *, ELEMENT_TYPE *>::value, weak_ptr<ELEMENT_TYPE>&>::type weak_ptr<ELEMENT_TYPE>::operator=(const weak_ptr<COMPATIBLE_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { #if 1 weak_ptr tmp(rhs); tmp.swap(*this); #else // needs friendship, or use the cheating util class. privateAssign(rhs.d_rep_p, rhs.d_ptr_p); #endif return *this; } template <class ELEMENT_TYPE> inline void weak_ptr<ELEMENT_TYPE>::reset() BSLS_KEYWORD_NOEXCEPT { if (d_rep_p) { d_rep_p->releaseWeakRef(); } d_ptr_p = 0; d_rep_p = 0; } template <class ELEMENT_TYPE> inline void weak_ptr<ELEMENT_TYPE>::swap(weak_ptr<ELEMENT_TYPE>& other) BSLS_KEYWORD_NOEXCEPT { // We directly implement swapping of two pointers, rather than simply // calling 'bsl::swap' or using 'bslalg::SwapUtil', to avoid (indirectly) // including the platform <algorithm> header, which may transitively // include other standard headers. This reduces the risk of // platform-specific cycles, which have been observed to cause problems. ELEMENT_TYPE *tempPtr_p = d_ptr_p; d_ptr_p = other.d_ptr_p; other.d_ptr_p = tempPtr_p; BloombergLP::bslma::SharedPtrRep *tempRep_p = d_rep_p; d_rep_p = other.d_rep_p; other.d_rep_p = tempRep_p; } // ACCESSORS template <class ELEMENT_TYPE> inline bool weak_ptr<ELEMENT_TYPE>::expired() const BSLS_KEYWORD_NOEXCEPT { return !(d_rep_p && d_rep_p->numReferences()); } template <class ELEMENT_TYPE> shared_ptr<ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>::lock() const BSLS_KEYWORD_NOEXCEPT { if (d_rep_p && d_rep_p->tryAcquireRef()) { return shared_ptr<ELEMENT_TYPE>( d_ptr_p, d_rep_p, BloombergLP::bslstl::SharedPtr_RepFromExistingSharedPtr()); // RETURN } return shared_ptr<ELEMENT_TYPE>(); } template <class ELEMENT_TYPE> template <class ANY_TYPE> inline bool weak_ptr<ELEMENT_TYPE>::owner_before(const shared_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT { return std::less<BloombergLP::bslma::SharedPtrRep *>()(d_rep_p, other.rep()); } template <class ELEMENT_TYPE> template <class ANY_TYPE> inline bool weak_ptr<ELEMENT_TYPE>::owner_before(const weak_ptr<ANY_TYPE>& other) const BSLS_KEYWORD_NOEXCEPT { return std::less<BloombergLP::bslma::SharedPtrRep *>()(d_rep_p, other.d_rep_p); } template <class ELEMENT_TYPE> inline BloombergLP::bslma::SharedPtrRep *weak_ptr<ELEMENT_TYPE>::rep() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p; } template <class ELEMENT_TYPE> inline long weak_ptr<ELEMENT_TYPE>::use_count() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p ? d_rep_p->numReferences() : 0; } #ifndef BDE_OMIT_INTERNAL_DEPRECATED // DEPRECATED BDE LEGACY ACCESSORS template <class ELEMENT_TYPE> inline shared_ptr<ELEMENT_TYPE> weak_ptr<ELEMENT_TYPE>::acquireSharedPtr() const BSLS_KEYWORD_NOEXCEPT { return lock(); } template <class ELEMENT_TYPE> inline int weak_ptr<ELEMENT_TYPE>::numReferences() const BSLS_KEYWORD_NOEXCEPT { return d_rep_p ? d_rep_p->numReferences() : 0; } #endif // BDE_OMIT_INTERNAL_DEPRECATED } // close namespace bsl namespace BloombergLP { namespace bslstl { // ----------------- // SharedPtr_ImpUtil // ----------------- template <class SHARED_TYPE, class ENABLE_TYPE> inline void SharedPtr_ImpUtil::loadEnableSharedFromThis( const bsl::enable_shared_from_this<ENABLE_TYPE> *result, bsl::shared_ptr<SHARED_TYPE> *sharedPtr) { BSLS_ASSERT(0 != sharedPtr); if (0 != result && result->d_weakThis.expired()) { result->d_weakThis.privateAssign( sharedPtr->d_rep_p, const_cast <ENABLE_TYPE *>( static_cast<ENABLE_TYPE const*>(sharedPtr->d_ptr_p))); } } inline void bslstl::SharedPtr_ImpUtil::loadEnableSharedFromThis(const volatile void *, const void *) BSLS_KEYWORD_NOEXCEPT { } template <class TYPE> inline TYPE *SharedPtr_ImpUtil::unqualify(const volatile TYPE *address) BSLS_KEYWORD_NOEXCEPT { return const_cast<TYPE *>(address); } template <class TYPE> inline void *SharedPtr_ImpUtil::voidify(TYPE *address) BSLS_KEYWORD_NOEXCEPT { return static_cast<void *>( const_cast<typename bsl::remove_cv<TYPE>::type *>(address)); } // -------------------- // struct SharedPtrUtil // -------------------- // CLASS METHODS template <class TARGET, class SOURCE> inline void SharedPtrUtil::constCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source) { BSLS_ASSERT(0 != target); target->reset(source, const_cast<TARGET *>(source.get())); } template <class TARGET, class SOURCE> inline bsl::shared_ptr<TARGET> SharedPtrUtil::constCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT { return bsl::shared_ptr<TARGET>(source, const_cast<TARGET *>(source.get())); } template <class TARGET, class SOURCE> inline void SharedPtrUtil::dynamicCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source) { BSLS_ASSERT(0 != target); if (TARGET *castPtr = dynamic_cast<TARGET *>(source.get())) { target->reset(source, castPtr); } else { target->reset(); } } template <class TARGET, class SOURCE> inline bsl::shared_ptr<TARGET> SharedPtrUtil::dynamicCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT { if (TARGET *castPtr = dynamic_cast<TARGET *>(source.get())) { return bsl::shared_ptr<TARGET>(source, castPtr); // RETURN } return bsl::shared_ptr<TARGET>(); } template <class TARGET, class SOURCE> inline void SharedPtrUtil::staticCast(bsl::shared_ptr<TARGET> *target, const bsl::shared_ptr<SOURCE>& source) { BSLS_ASSERT(0 != target); target->reset(source, static_cast<TARGET *>(source.get())); } template <class TARGET, class SOURCE> inline bsl::shared_ptr<TARGET> SharedPtrUtil::staticCast(const bsl::shared_ptr<SOURCE>& source) BSLS_KEYWORD_NOEXCEPT { return bsl::shared_ptr<TARGET>(source, static_cast<TARGET *>(source.get())); } // -------------------------- // struct SharedPtrNilDeleter // -------------------------- // ACCESSORS inline void SharedPtrNilDeleter::operator()(const volatile void *) const BSLS_KEYWORD_NOEXCEPT { } // ------------------------------- // struct SharedPtr_DefaultDeleter // ------------------------------- // ACCESSORS template <> template <class ANY_TYPE> inline void SharedPtr_DefaultDeleter<true>::operator()(ANY_TYPE *ptr) const BSLS_KEYWORD_NOEXCEPT { delete [] ptr; } template <> template <class ANY_TYPE> inline void SharedPtr_DefaultDeleter<false>::operator()(ANY_TYPE *ptr) const BSLS_KEYWORD_NOEXCEPT { delete ptr; } // -------------------------- // class SharedPtr_RepProctor // -------------------------- // CREATORS inline SharedPtr_RepProctor::SharedPtr_RepProctor(bslma::SharedPtrRep *rep) BSLS_KEYWORD_NOEXCEPT : d_rep_p(rep) { } inline SharedPtr_RepProctor::~SharedPtr_RepProctor() { if (d_rep_p) { d_rep_p->disposeRep(); } } // MANIPULATORS inline void SharedPtr_RepProctor::release() BSLS_KEYWORD_NOEXCEPT { d_rep_p = 0; } } // close package namespace } // close enterprise namespace // FREE OPERATORS template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator==(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return lhs.get() == rhs.get(); } template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator!=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !(lhs == rhs); } template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator<(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return std::less<const void *>()(lhs.get(), rhs.get()); } template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator>(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return rhs < lhs; } template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator<=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !(rhs < lhs); } template <class LHS_TYPE, class RHS_TYPE> inline bool bsl::operator>=(const shared_ptr<LHS_TYPE>& lhs, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !(lhs < rhs); } template <class LHS_TYPE> inline bool bsl::operator==(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return !lhs; } template <class RHS_TYPE> inline bool bsl::operator==(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !rhs; } template <class LHS_TYPE> inline bool bsl::operator!=(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return static_cast<bool>(lhs); } template <class RHS_TYPE> inline bool bsl::operator!=(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return static_cast<bool>(rhs); } template <class LHS_TYPE> inline bool bsl::operator<(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return std::less<LHS_TYPE *>()(lhs.get(), 0); } template <class RHS_TYPE> inline bool bsl::operator<(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return std::less<RHS_TYPE *>()(0, rhs.get()); } template <class LHS_TYPE> inline bool bsl::operator<=(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return !std::less<LHS_TYPE *>()(0, lhs.get()); } template <class RHS_TYPE> inline bool bsl::operator<=(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !std::less<RHS_TYPE *>()(rhs.get(), 0); } template <class LHS_TYPE> inline bool bsl::operator>(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return std::less<LHS_TYPE *>()(0, lhs.get()); } template <class RHS_TYPE> inline bool bsl::operator>(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return std::less<RHS_TYPE *>()(rhs.get(), 0); } template <class LHS_TYPE> inline bool bsl::operator>=(const shared_ptr<LHS_TYPE>& lhs, bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT { return !std::less<LHS_TYPE *>()(lhs.get(), 0); } template <class RHS_TYPE> inline bool bsl::operator>=(bsl::nullptr_t, const shared_ptr<RHS_TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT { return !std::less<RHS_TYPE *>()(0, rhs.get()); } template <class CHAR_TYPE, class CHAR_TRAITS, class ELEMENT_TYPE> inline std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>& bsl::operator<<(std::basic_ostream<CHAR_TYPE, CHAR_TRAITS>& stream, const shared_ptr<ELEMENT_TYPE>& rhs) { return stream << rhs.get(); } // ASPECTS template <class HASHALG, class ELEMENT_TYPE> inline void bsl::hashAppend(HASHALG& hashAlg, const shared_ptr<ELEMENT_TYPE>& input) { hashAppend(hashAlg, input.get()); } template <class ELEMENT_TYPE> inline void bsl::swap(shared_ptr<ELEMENT_TYPE>& a, shared_ptr<ELEMENT_TYPE>& b) BSLS_KEYWORD_NOEXCEPT { a.swap(b); } template <class ELEMENT_TYPE> inline void bsl::swap(weak_ptr<ELEMENT_TYPE>& a, weak_ptr<ELEMENT_TYPE>& b) BSLS_KEYWORD_NOEXCEPT { a.swap(b); } // STANDARD FREE FUNCTIONS template<class DELETER, class ELEMENT_TYPE> inline DELETER *bsl::get_deleter(const shared_ptr<ELEMENT_TYPE>& p) BSLS_KEYWORD_NOEXCEPT { BloombergLP::bslma::SharedPtrRep *rep = p.rep(); return rep ? static_cast<DELETER *>(rep->getDeleter(typeid(DELETER))) : 0; } // STANDARD CAST FUNCTIONS template<class TO_TYPE, class FROM_TYPE> inline bsl::shared_ptr<TO_TYPE> bsl::const_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT { return shared_ptr<TO_TYPE>(source, const_cast<TO_TYPE *>(source.get())); } template<class TO_TYPE, class FROM_TYPE> inline bsl::shared_ptr<TO_TYPE> bsl::dynamic_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT { if (TO_TYPE *castPtr = dynamic_cast<TO_TYPE *>(source.get())) { return shared_ptr<TO_TYPE>(source, castPtr); // RETURN } return shared_ptr<TO_TYPE>(); } template<class TO_TYPE, class FROM_TYPE> inline bsl::shared_ptr<TO_TYPE> bsl::static_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT { return shared_ptr<TO_TYPE>(source, static_cast<TO_TYPE *>(source.get())); } template<class TO_TYPE, class FROM_TYPE> inline bsl::shared_ptr<TO_TYPE> bsl::reinterpret_pointer_cast(const shared_ptr<FROM_TYPE>& source) BSLS_KEYWORD_NOEXCEPT { return shared_ptr<TO_TYPE>(source, reinterpret_cast<TO_TYPE *>(source.get())); } // STANDARD FACTORY FUNCTIONS #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14 // C++11, PERFECT FORWARDING THROUGH A VARIADIC TEMPLATE template<class ELEMENT_TYPE, class ALLOC, class... ARGS> # if defined(BSLSTL_SHAREDPTR_NO_PARTIAL_ORDER_ON_ALLOCATOR_POINTER) typename bsl::enable_if<!bsl::is_pointer<ALLOC>::value && !bsl::is_array<ELEMENT_TYPE>::value, bsl::shared_ptr<ELEMENT_TYPE> >::type # else typename bsl::enable_if<!bsl::is_array<ELEMENT_TYPE>::value, bsl::shared_ptr<ELEMENT_TYPE> >::type # endif bsl::allocate_shared(ALLOC basicAllocator, ARGS&&... args) { typedef BloombergLP::bslstl::SharedPtr_ImpUtil ImpUtil; typedef BloombergLP::bslstl::SharedPtrAllocateInplaceRep<ELEMENT_TYPE, ALLOC> Rep; Rep *rep_p = Rep::makeRep(basicAllocator); BloombergLP::bslstl::SharedPtr_RepProctor proctor(rep_p); bsl::allocator_traits<ALLOC>::construct( basicAllocator, ImpUtil::unqualify(rep_p->ptr()), BSLS_COMPILERFEATURES_FORWARD(ARGS,args)...); proctor.release(); return shared_ptr<ELEMENT_TYPE>(rep_p->ptr(), rep_p); } template<class ELEMENT_TYPE, class ALLOC, class... ARGS> inline typename bsl::enable_if<!bsl::is_array<ELEMENT_TYPE>::value, bsl::shared_ptr<ELEMENT_TYPE> >::type bsl::allocate_shared(ALLOC *basicAllocator, ARGS&&... args) { typedef BloombergLP::bslstl::SharedPtr_ImpUtil ImpUtil; typedef bsl::allocator<char> AllocatorType; typedef bsl::allocator_traits<AllocatorType> AllocatorTraits; typedef BloombergLP::bslstl::SharedPtrAllocateInplaceRep< ELEMENT_TYPE, AllocatorType> Rep; AllocatorType alloc(basicAllocator); Rep *rep_p = Rep::makeRep(alloc); BloombergLP::bslstl::SharedPtr_RepProctor proctor(rep_p); AllocatorTraits::construct(alloc, ImpUtil::unqualify(rep_p->ptr()), BSLS_COMPILERFEATURES_FORWARD(ARGS,args)...); proctor.release(); return shared_ptr<ELEMENT_TYPE>(rep_p->ptr(), rep_p); } // 'make_shared' using the default allocator template<class ELEMENT_TYPE, class... ARGS> inline typename bsl::enable_if<!bsl::is_array<ELEMENT_TYPE>::value, bsl::shared_ptr<ELEMENT_TYPE> >::type bsl::make_shared(ARGS&&... args) { typedef BloombergLP::bslstl::SharedPtr_ImpUtil ImpUtil; typedef bsl::allocator<char> AllocatorType; typedef BloombergLP::bslstl::SharedPtrAllocateInplaceRep< ELEMENT_TYPE, AllocatorType> Rep; AllocatorType basicAllocator; Rep *rep_p = Rep::makeRep(basicAllocator); BloombergLP::bslstl::SharedPtr_RepProctor proctor(rep_p); ::new (ImpUtil::voidify(rep_p->ptr())) ELEMENT_TYPE( BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); proctor.release(); return shared_ptr<ELEMENT_TYPE>(rep_p->ptr(), rep_p); } #endif // ============================================================================ // TYPE TRAITS // ============================================================================ // Type traits for smart pointers: //: o 'shared_ptr' has pointer semantics, but 'weak_ptr' does not. //: //: o Although 'shared_ptr' constructs with an allocator, it does not 'use' an //: allocator in the manner of the 'UsesBslmaAllocator' trait, and should be //: explicitly specialized as a clear sign to code inspection tools. //: //: o Smart pointers are bitwise-movable as long as there is no opportunity for //: holding a pointer to internal state in the immediate object itself. As //: 'd_ptr_p' is never exposed by reference, it is not possible to create an //: internal pointer, so the trait should be 'true'. namespace BloombergLP { namespace bslma { template <class ELEMENT_TYPE> struct UsesBslmaAllocator< ::bsl::shared_ptr<ELEMENT_TYPE> > : bsl::false_type {}; } // close namespace bslma namespace bslmf { template <class ELEMENT_TYPE> struct HasPointerSemantics< ::bsl::shared_ptr<ELEMENT_TYPE> > : bsl::true_type {}; template <class ELEMENT_TYPE> struct IsBitwiseMoveable< ::bsl::shared_ptr<ELEMENT_TYPE> > : bsl::true_type {}; template <class ELEMENT_TYPE> struct IsBitwiseMoveable< ::bsl::weak_ptr<ELEMENT_TYPE> > : bsl::true_type {}; } // close namespace bslmf } // close enterprise namespace #if defined(BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC) # pragma GCC diagnostic pop #endif #undef BSLSTL_SHAREDPTR_DECLARE_IF_CONVERTIBLE #undef BSLSTL_SHAREDPTR_DEFINE_IF_CONVERTIBLE #undef BSLSTL_SHAREDPTR_DECLARE_IF_COMPATIBLE #undef BSLSTL_SHAREDPTR_DEFINE_IF_COMPATIBLE #undef BSLSTL_SHAREDPTR_DECLARE_IF_DELETER #undef BSLSTL_SHAREDPTR_DEFINE_IF_DELETER #undef BSLSTL_SHAREDPTR_DECLARE_IF_NULLPTR_DELETER #undef BSLSTL_SHAREDPTR_DEFINE_IF_NULLPTR_DELETER #undef BSLSTL_SHAREDPTR_SFINAE_DISCARD #endif // End C++11 code #endif // ---------------------------------------------------------------------------- // Copyright 2023 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------