// slbRCPtr.h -- Reference counting smart pointer. // (c) Copyright Schlumberger Technology Corp., unpublished work, created // 1999. This computer program includes Confidential, Proprietary // Information and is a Trade Secret of Schlumberger Technology Corp. All // use, disclosure, and/or reproduction is prohibited unless authorized // in writing. All Rights Reserved. #if !defined(SLB_RCPTR_H) #define SLB_RCPTR_H #include "slbRCComp.h" #include "slbRCObj.h" namespace slbRefCnt { // template class RCPtr -- Reference Counting Pointer // // The RCPtr template implements a variant of the "Counted Pointer" // idiom. RCPtr is a reference counting smart pointer-to-T object // where T must inherit from RCObject (reference counted objects, see // slbRCObj.h). // // C is the comparator class to use in performing the pointer // comparison operations, defaulting to ShallowComparator. See // slbRComp.h for more information. // // The template's original design was inspired by the reference // counting idiom described by Item #29 in the book "More Effective // C++," Scott Meyers, Addison-Wesley, 1996. // // CONTRAINTS: RCPtr can only be used for reference counting those // objects for which you have the source because RCPtr only reference // objects derived from RCObject. See GRCPtr in slbGRCPtr.h for // reference counting objects when you don't have access to the source // of the class to reference count. // // RCPtr should not be used as a base class. // // CAVEATS: The client should not use the Dummy * conversion // operator. The definition allows smart pointer comparisons. See // slbRCComp.h for more information. template > class RCPtr { public: // Types typedef T ValueType; // PrivateDummy is a helper class to support validity testing of a // pointer. This class together with the conversion operator // PrivateDummy const *() below allows smart pointers to be tested // for nullness (validity tests). In other words, comparing // pointers in a syntactically natural way without allowing // heterogeneous comparisons and that won't violate the // protections that RCPtr provides. The technique is from an // article by Don Box in "Com Smart Pointers Also Considered // Harmful," 1996, C++ Report. // // CAVEAT: There is a defect in the at least with MSVC++ 6.0 where // constructs testing the pointer for nullness will fail to // compile with a error message in the Release configuration but // compile successfully in Debug. For example, // // if (p) ... // // where p is an RCPtr or GRCPtr may fail to compile in the // Release configuration. // // CAVEAT: Although the PrivateDummy and the conversion operator // has public access to the pointer of the object being counted // (RCObject *), a C-style or reinterpret_cast cast would have to // be used. As in all cases using those cast // constructs--programmer beware. // // DESIGN NOTE: The helper class is functionally the same as the // one in the RCPtr template. In a previous release, this dummy // class was made into a template and shared with both RCPtr and // GRCPtr. However, casual compilation tests with MSVC++ 6.0 indicate // compilation with a dummy local to each class resulted in // noticable faster compilations using a test suite. Rather than // suffer repeatedly slower compilations, the helper was made // local to each user. class PrivateDummy {}; // Constructors/Destructors RCPtr(T *pReal = 0); RCPtr(RCPtr const &rhs); ~RCPtr(); // Operators RCPtr &operator=(RCPtr const &rhs); // Enable validity test of RCPtr. See the explanation in // slbRCComp.h. operator PrivateDummy const *() const { return reinterpret_cast(m_pointee); } // Access T *operator->() const; T &operator*() const; private: // Operations void Init(); // Variables T *m_pointee; }; template RCPtr::RCPtr(T *pReal) : m_pointee(pReal) { Init(); } template RCPtr::RCPtr(RCPtr const &rhs) : m_pointee(rhs.m_pointee) { Init(); } template RCPtr::~RCPtr() { try { if (m_pointee) m_pointee->RemoveReference(); } catch (...) { // don't allow exceptions to propagate out of destructor } } template RCPtr & RCPtr::operator=(RCPtr const &rhs) { if (m_pointee != rhs.m_pointee) { if (m_pointee) m_pointee->RemoveReference(); m_pointee = rhs.m_pointee; Init(); } return *this; } template T * RCPtr::operator->() const { return m_pointee; } template T & RCPtr::operator*() const { return *m_pointee; } template bool operator==(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return Comp.Equates(lhs.operator->(), rhs.operator->()); } template bool operator!=(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return !Comp.Equates(lhs.operator->(), rhs.operator->()); } template bool operator<(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return Comp.IsLess(lhs.operator->(), rhs.operator->()); } template bool operator>(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return Comp.IsLess(rhs.operator->(), lhs.operator->()); } template bool operator<=(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return !Comp.IsLess(rhs.operator->(), lhs.operator->()); } template bool operator>=(RCPtr const &lhs, RCPtr const &rhs) { C Comp; return !Comp.IsLess(lhs.operator->(), rhs.operator->()); } template void RCPtr::Init() { if (m_pointee) m_pointee->AddReference(); } } // namespace #endif // SLB_RCPTR_H