// bslma_sharedptrrep.h -*-C++-*- #ifndef INCLUDED_BSLMA_SHAREDPTRREP #define INCLUDED_BSLMA_SHAREDPTRREP #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide an abstract class for a shared object manager. // //@CLASSES: // bslma::SharedPtrRep : shared pointer representation abstract class // //@SEE_ALSO: bslstl_sharedptr, bslma_sharedptrrep_inplace, // bslma_sharedptrrep_outofplace // //@DESCRIPTION: This component provides a partially implemented abstract class, // 'bslma::SharedPtrRep', for managing the lifetime of a shared object. // 'bslma::SharedPtrRep' provides a count of both shared and weak references to // a shared object (described in more detail in the next section). In // addition, 'bslma::SharedPtrRep' provides protocol methods that allows a // concrete implementation to specify what action should be taken when these // reference counts reach zero. // ///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. The function 'acquireRef' should be // called when a new shared reference is created and 'releaseRef' should be // called when a share reference is removed. // // 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. The function // 'acquireWeakRef' should be called when a new weak reference is created and // 'releaseWeakRef' should be called when a weak reference is removed. // ///Thread Safety ///------------- // 'bslma::SharedPtrRep' is thread-safe provided that 'disposeObject' and // 'disposeRep' are not called explicitly, meaning that all non-creator // operations other than 'disposeObject' and 'disposeRep' on a given instance // can be safely invoked simultaneously from multiple threads ('disposeObject' // and 'disposeRep' are meant to be implemented by types inheriting // 'bslma::SharedPtrRep', and invoked only by 'releaseRef' and // 'releaseWeakRef'). Note that there is no thread safety guarantees for // operations on the managed object. // ///'disposeObject' and 'disposeRep' ///-------------------------------- // 'disposeObject' is meant to act as the destructor of the managed object and // each derived class must override this method to perform an action that // releases the shared object from management, such as deleting the managed // object. 'disposeObject' will be called when the last shared reference to // the object has been released using 'releaseRef'. // // 'disposeRep' is meant to act as the destructor of 'bslma::SharedPtrRep'. // The destructor of 'bslma::SharedPtrRep' is declared as private and cannot be // called. The derived class must override 'disposeRep' to perform an action // such as deallocating the memory of the instance of the derived class. // 'disposeRep' will be called when both the last shared reference and the last // weak reference to the object has been released using 'releaseRef' or // 'releaseWeakRef'. // ///Usage ///----- // The following example demonstrates how to implement a shared // 'bdlt::Datetime' using 'bslma::SharedPtrRep'. In this example, the // implementation will store an object of 'bdlt::Datetime' in-place. First, we // define an implementation of 'bslma::SharedPtrRep': //.. // class MySharedDatetimeRepImpl : public bslma::SharedPtrRep { // // Implementation of 'bslma::SharedPtrRep' for an in-place // // 'bdlt::Datetime' object. // // // DATA // bslma::Allocator *d_allocator_p; // memory allocator (held, not owned) // bdlt::Datetime d_instance; // in-place object // // private: // // NOT IMPLEMENTED // MySharedDatetimeRepImpl(const MySharedDatetimeRepImpl&); // MySharedDatetimeRepImpl& operator=(const MySharedDatetimeRepImpl&); // // public: // // CREATORS // MySharedDatetimeRepImpl(bslma::Allocator *basicAllocator, // int year, // int month, // int day); // // Create a shared representation of a 'bdlt::Datetime' object // // having the specified 'year', 'month' and 'day' using the // // specified 'basicAllocator' to supply memory. // // // MANIPULATORS // virtual void disposeRep(); // // Dispose of this 'MySharedDatetimeRepImpl' object. // // virtual void disposeObject(); // // Dispose of the managed 'bdlt::Datetime' object. // // // ACCESSORS // bdlt::Datetime *ptr(); // // Return the address of the modifiable managed 'bdlt::Datetime' // // object. // // virtual void *originalPtr() const; // // Return the address of the modifiable managed 'bdlt::Datetime' // // object. // }; //.. // Next, we define the implementation: //.. // // CREATORS // MySharedDatetimeRepImpl::MySharedDatetimeRepImpl( // bslma::Allocator *basicAllocator, // int year, // int month, // int day) // : d_allocator_p(basicAllocator) // , d_instance(year, month, day) // { // } // // void MySharedDatetimeRepImpl::disposeRep() // { // d_allocator_p->deallocate(this); // } // // void MySharedDatetimeRepImpl::disposeObject() // { // d_instance.~bdlt::Datetime(); // } // // bdlt::Datetime *MySharedDatetimeRepImpl::ptr() // { // return &d_instance; // } // // void *MySharedDatetimeRepImpl::originalPtr() const { // return const_cast<void*>(static_cast<const void *>(&d_instance)); // } //.. // Next, we implement a shared 'bdlt::Datetime' class. //.. // class MySharedDatetimePtr { // // This class provides a reference counted managed pointer to support // // shared ownership of a 'bdlt::Datetime' object. // // bdlt::Datetime *d_ptr_p; // pointer to the managed object // bslma::SharedPtrRep *d_rep_p; // pointer to the representation object // // private: // // NOT IMPLEMENTED // MySharedDatetimePtr& operator=(const MySharedDatetimePtr&); // // public: // // CREATORS // MySharedDatetimePtr(); // // Create an empty shared datetime. // // MySharedDatetimePtr(bdlt::Datetime* ptr, bslma::SharedPtrRep* rep); // // Create a shared datetime that adopts ownership of the specified // // 'ptr' and the specified 'rep'. // // MySharedDatetimePtr(const MySharedDatetimePtr& original); // // Create a shared datetime that refers to the same object managed // // by the specified 'original' // // ~MySharedDatetimePtr(); // // Destroy this shared datetime and release the reference to the // // 'bdlt::Datetime' object to which it might be referring. If this // // is the last shared reference, deleted the managed object. // // // MANIPULATORS // void createInplace(bslma::Allocator *basicAllocator, // int year, // int month, // int day); // // Create a new 'MySharedDatetimeRepImpl', using the specified // // 'basicAllocator' to supply memory, using the specified 'year', // // 'month' and 'day' to initialize the 'bdlt::Datetime' within the // // newly created 'MySharedDatetimeRepImpl', and make this // // object refer to the newly created 'bdlt::Datetime' object. // // // ACCESSORS // bdlt::Datetime& operator*() const; // // Return a reference to the modifiable 'bdlt::Datetime' to which // // this object refers. // // bdlt::Datetime *operator->() const; // // Return the address of the modifiable 'bdlt::Datetime' to which // // this object refers. // // bdlt::Datetime *ptr() const; // // Return the address of the modifiable 'bdlt::Datetime' to which // // this object refers. // }; //.. // Finally, we implement 'MySharedDatetimePtr': //.. // MySharedDatetimePtr::MySharedDatetimePtr() // : d_ptr_p(0) // , d_rep_p(0) // { // } // // MySharedDatetimePtr::MySharedDatetimePtr(bdlt::Datetime *ptr, // bslma::SharedPtrRep *rep) // : d_ptr_p(ptr) // , d_rep_p(rep) // { // } // // MySharedDatetimePtr::MySharedDatetimePtr( // const MySharedDatetimePtr& original) // : d_ptr_p(original.d_ptr_p) // , d_rep_p(original.d_rep_p) // { // if (d_ptr_p) { // d_rep_p->acquireRef(); // } else { // d_rep_p = 0; // } // } // // MySharedDatetimePtr::~MySharedDatetimePtr() // { // if (d_rep_p) { // d_rep_p->releaseRef(); // } // } // // void MySharedDatetimePtr::createInplace(bslma::Allocator *basicAllocator, // int year, // int month, // int day) // { // basicAllocator = bslma::Default::allocator(basicAllocator); // MySharedDatetimeRepImpl *rep = new (*basicAllocator) // MySharedDatetimeRepImpl(basicAllocator, // year, // month, // day); // MySharedDatetimePtr temp(rep->ptr(), rep); // bsl::swap(d_ptr_p, temp.d_ptr_p); // bsl::swap(d_rep_p, temp.d_rep_p); // } // // bdlt::Datetime& MySharedDatetimePtr::operator*() const // { // return *d_ptr_p; // } // // bdlt::Datetime *MySharedDatetimePtr::operator->() const // { // return d_ptr_p; // } // // bdlt::Datetime *MySharedDatetimePtr::ptr() const // { // return d_ptr_p; // } //.. #include <bslscm_version.h> #include <bsls_assert.h> #include <bsls_atomic.h> #include <typeinfo> namespace BloombergLP { namespace bslma { // ================== // class SharedPtrRep // ================== class SharedPtrRep { // This class provides a partially implemented shared pointer // representation ("letter") protocol. The class provides two counters for // storing the number of shared and weak references, and functions to // increment and decrement these counters. In addition, this class // provides protocol methods that allow concrete implementations to specify // what action should be taken when these counts reach zero. The function // 'disposeRep' is responsible for destroying this object, it is called // when the reference count to this object reaches zero. Thus, the // destructor of this object is declared as protected and should never be // invoked. // DATA bsls::AtomicInt d_adjustedSharedCount; // Counter storing a value that allows us to // calculate the number of shared references. // The numerical value of 'd_adjustedSharedCount' // is: 2 * number of shared references, plus 1 if // any weak references were *ever* created. bsls::AtomicInt d_adjustedWeakCount; // Counter storing a value that allows us to // calculate the number of weak references. The // numerical value of 'd_adjustedWeakCount' is: // 2 * number of weak references, plus 1 if there // are any *outstanding* shared references. private: // NOT IMPLEMENTED SharedPtrRep(const SharedPtrRep&); // = delete SharedPtrRep& operator=(const SharedPtrRep&); // = delete protected: // PROTECTED CREATORS virtual ~SharedPtrRep(); // Destroy this representation object. Note that this destructor is // not intended to be invoked polymorphically, and is marked 'virtual' // only to silence frequent warnings on popular compilers. public: // CLASS METHODS static void managedPtrDeleter(void *, void *rep); // Release the shared reference to an object held by the 'SharedPtrRep' // object that is pointed to be by specified 'rep'. The behavior is // undefined unless 'rep' points to an object whose complete type // publicly and unambiguously derives from 'SharedPtrRep'. Note that // the first argument is ignored. Also note that this function serves // as the 'ManagedPtr' deleter when converting a 'bsl::shared_ptr' to a // 'bslma::ManagedPtr'. static void managedPtrEmptyDeleter(void *, void *rep); // This function has no effect. The behavior is undefined unless 'rep' // is null. Note that this function serves as the managed ptr deleter // when converting an empty or null 'bsl::shared_ptr' to a // 'bslma::ManagedPtr'. // CREATORS SharedPtrRep(); // Create a 'SharedPtrRep' object having one shared reference and no // weak references. // PURE VIRTUAL FUNCTIONS virtual void disposeObject() = 0; // Dispose of the shared object referred to by this representation. // This method is automatically invoked by 'releaseRef' when the number // of shared references reaches zero and should not be explicitly // invoked otherwise. Note that this virtual 'disposeObject' method // effectively serves as the shared object's destructor. Also note // that derived classes must override this method to perform the // appropriate action such as deleting the shared object. virtual void disposeRep() = 0; // Dispose of this representation object. This method is automatically // invoked by 'releaseRef' and 'releaseWeakRef' when the number of weak // references and the number of shared references both reach zero and // should not be explicitly invoked otherwise. The behavior is // undefined unless 'disposeObject' has already been called for this // representation. Note that this virtual 'disposeRep' method // effectively serves as the representation object's destructor. Also // note that derived classes must override this method to perform // appropriate action such as deleting this representation, or // returning it to an object pool. virtual void *getDeleter(const std::type_info& type) = 0; // Return a pointer to the deleter stored by the derived representation // (if any) if the deleter has the same type as that described by the // specified 'type', and a null pointer otherwise. Note that while // this methods appears to be a simple accessor, it is declared as non- // 'const' qualified to support representations storing the deleter // directly as a data member. virtual void *originalPtr() const = 0; // Return the (untyped) address of the modifiable shared object // referred to by this representation. // MANIPULATORS void acquireRef(); // Atomically acquire a shared reference to the shared object referred // to by this representation. The behavior is undefined unless // '0 < numReferences()'. void acquireWeakRef(); // Atomically acquire a weak reference to the shared object referred to // by this representation. The behavior is undefined unless // '0 < numWeakReferences() || 0 < numReferences()'. #ifndef BDE_OMIT_INTERNAL_DEPRECATED void incrementRefs(int incrementAmount = 1); // Atomically increment the number of shared references to the shared // object referred to by this representation by the optionally // specified 'incrementAmount'. The behavior is undefined unless // '0 < incrementAmount' and '0 < numReferences()'. // // DEPRECATED: Use 'acquireRef' instead. #endif // BDE_OMIT_INTERNAL_DEPRECATED void releaseRef(); // Atomically release a shared reference to the shared object referred // to by this representation, disposing of the shared object if all the // shared references to that object are released, and disposing of this // representation if all (shared and weak) references to that object // are released. The behavior is undefined unless // '0 < numReferences()'. void releaseWeakRef(); // Atomically release a weak reference to the shared object referred to // by this representation, disposing of this representation if all // (shared and weak) references to the shared object are released. The // behavior is undefined unless '0 < numWeakReferences()'. void resetCountsRaw(int numSharedReferences, int numWeakReferences); // Reset the number of shared references and the number of weak // references stored by this representation to the specified // 'numSharedReferences' and 'numWeakReferences' respectively. This // function is *not* thread-safe and users must ensure that they // serialize access to the 'SharedPtrRep' object when calling this // function. Note that this function updates the counts, but does not // dispose of the representation or the object irrespective of the // values of 'numSharedReferences' and 'numWeakReferences'. bool tryAcquireRef(); // Atomically acquire a shared reference to the shared object referred // to by this representation, if the number of shared references is // greater than 0, and do nothing otherwise. Return 'true' if the // acquire succeeds, and 'false' otherwise. The behavior is undefined // unless '0 < numWeakReferences() || 0 < numReferences()'. // ACCESSORS bool hasUniqueOwner() const; // Return 'true' if there is only one shared reference and no weak // references to the object referred to by this representation, and // 'false' otherwise. int numReferences() const; // Return a "snapshot" of the current number of shared references to // the shared object referred to by this representation object. int numWeakReferences() const; // Return a "snapshot" of the current number of weak references to the // shared object referred to by this representation object. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------ // class SharedPtrRep // ------------------ // PROTECTED CREATORS inline SharedPtrRep::~SharedPtrRep() { } // CLASS METHODS inline void SharedPtrRep::managedPtrDeleter(void *, void *rep) { BSLS_ASSERT_SAFE(rep); static_cast<SharedPtrRep *>(rep)->releaseRef(); } inline void SharedPtrRep::managedPtrEmptyDeleter(void *, void *rep) { BSLS_ASSERT_SAFE(!rep); (void)rep; // Silence unused argument warning in non-SAFE builds. } // CREATORS inline SharedPtrRep::SharedPtrRep() : d_adjustedSharedCount(2) // minimum consistency: relaxed , d_adjustedWeakCount(1) // minimum consistency: relaxed { } // MANIPULATORS inline void SharedPtrRep::acquireRef() { BSLS_ASSERT_SAFE(0 < numReferences()); d_adjustedSharedCount.addRelaxed(2); // minimum consistency: relaxed } #ifndef BDE_OMIT_INTERNAL_DEPRECATED inline void SharedPtrRep::incrementRefs(int incrementAmount) { BSLS_ASSERT_SAFE(0 < incrementAmount); BSLS_ASSERT_SAFE(0 < numReferences()); d_adjustedSharedCount.addRelaxed(incrementAmount * 2); // minimum consistency: relaxed } #endif // BDE_OMIT_INTERNAL_DEPRECATED inline void SharedPtrRep::releaseWeakRef() { BSLS_ASSERT_SAFE(0 < numWeakReferences()); const int weakCount = d_adjustedWeakCount.add(-2); // release consistency: acquire/release if (0 == weakCount) { disposeRep(); } } // ACCESSORS inline bool SharedPtrRep::hasUniqueOwner() const { const int sharedCount = d_adjustedSharedCount; // release consistency: acquire return 2 == sharedCount || (3 == sharedCount && 1 == d_adjustedWeakCount); // release consistency: acquire } inline int SharedPtrRep::numReferences() const { const int sharedCount = d_adjustedSharedCount.loadRelaxed(); // minimum consistency: relaxed return sharedCount / 2; } inline int SharedPtrRep::numWeakReferences() const { const int weakCount = d_adjustedWeakCount.loadRelaxed(); // minimum consistency: relaxed return weakCount / 2; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2013 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 ----------------------------------