// Ptr.h #ifndef Ptr_H #define Ptr_H // Defines the base pointer class Ptr. // // David Adams // Rice University // adams@physics.rice.edu // 11mar98 // // Updates: // // 18mar98 dla // Allow implicit conversion from T*. Drop explicit comparison // operators (==,<,etc). // // 24mar98 dla // Add automatic conversion to const void* to enable // if ( pa ) ... // if ( ! pa ) ... // if ( pa == pb ) ... // // 25mar98 dla // Change operator<< to write only the address and add method print // to write detailed information. // // 25mar98 dla // The policy attribute has been made mutable and the arguments for // copy and assignment are now const. // // 16apr98 dla // Drop delete_object method. Call _pol.invalidate(_point) instead // of set_invalid() and let the policy delete the object. // This way pointers with policies which do not delete, do not // require physical coupling for the destructor. // // 29may98 dla // Make constructor explicit unless PTR_NO_EPLICIT_CONSTRUCTOR is // defined. // // 13jan99 dla // Rename Policy::invalidate(T*) to Policy::delete_if_managing(T*). // The policy is expected to delete the passed pointer if and only // if it has exclusive management. // // These pointers can be used to point to any user-defined class. // The CSET compiler complains if they are used with native types // because of operator->. // // The instantiation Ptr px behaves much like X* in that it provides // dereferencing (*px) and member selection (px->member). The underlying // bare pointer may be obtained with px.pointer(). Conversion to const // void* allows a direct check of validity using pointer syntax: // "if ( px ) ...". Comparisons (==, < , ...) may be made with other // Ptr template objects or with bare pointers according to the usual // rules for pointers. // // Ptr objects may be constructed from or assigned from bare pointers // or other Ptr objects of the same or different type according to // the same rules by which bare pointers are assigned. There is some // loss of functionality and safety if the compiler does not allow // template member functions. // // The behavior of const pointers (const X*) may be obtained by using // a const type: Ptr. This does not work for compilers which // are unable to delete const pointers. // // This class is intended to be used as a base class. Subclasses can // override the method pointer() to provide capabilities such as // reference counting or deferred I/O fromi/to persistent media. // // There is no automatic conversion to a bare pointer. Use method // pointer() to access the underlying bare pointer. // // Requirements for template argments in Ptr: // T is any C++ or user-defined class and can be const. // P must satisfy the interface described in AbsPolicy. // #include "ptr/PtrException.h" #include "ptr/NullPolicy.h" #include #ifdef NT_MSVCPP #include #endif // If member templates are not supported, include the AbsPolicy header // file. This triggers methods which assume all policies inherit from // AbsPolicy in lieu of templated member functions. #ifdef DEFECT_NO_MEMBER_TEMPLATES_AT_ALL #include "ptr/AbsPolicy.h" #endif // Class which enables automatic conversion needed when AbsPolicy // is used in place of templated member functions. #ifdef AbsPolicy_H class TmpPtr { private: const void* _point; AbsPolicy& _policy; public: TmpPtr(const void* point, AbsPolicy& policy) : _point(point), _policy(policy) { } const void* pointer() const { return _point; } AbsPolicy& policy() const { return _policy; }; }; #endif #ifndef DEFECT_NO_DEFAULT_TEMPLATE_PARAMETERS template #else template #endif class Ptr { private: // Count the number of pointers of this type. // This is for simple leak checking. static int _count; public: // Return the number of pointers of this type. static int get_count( ) { return _count; } private: // attributes // Bare C++ pointer (address). T* _point; // Policy. #ifndef DEFECT_NO_MUTABLE mutable #endif P _policy; private: // methods // return true if policy is valid and pointer is defined bool is_valid() const { return _policy.is_valid() && _point!=0; } public: // Constructors, destructor and assignment operators. // Constructor from bare pointer // Compiles if underlying pointer conversion is allowed. #ifndef DEFECT_NO_EXPLICIT #ifndef PTR_NO_EXPLICIT_CONSTRUCTOR explicit #endif #endif Ptr(T* point =0) : _point(point), _policy(point) { ++_count; } // Destructor. virtual ~Ptr() { _policy.delete_if_managing(_point); --_count; } #ifndef AbsPolicy_H /* standards-compliant compiler */ // Safe interface for compilers which allow // member template functions. // Constructor from other types of Ptr objects. // Compiles if underlying pointer conversion is allowed. template Ptr(const Ptr& rhs) : _point(rhs.pointer()), _policy(rhs.pointer(), rhs.policy() ) { ++_count; } // Assignment from any other type of Ptr. // Compiles if underlying pointer conversion is allowed. template Ptr& operator=(const Ptr& rhs) { _policy.delete_if_managing(_point); _point = rhs.pointer(); _policy = P(_point,rhs.policy()); return *this; } // Assignment from a bare pointer. // Compiles if underlying pointer conversion is allowed. template Ptr& operator=(T2* rhs) { _policy.delete_if_managing(_point); _point = rhs; _policy = P(_point); return *this; } // Assignment from any other type of Ptr casting away const. // Compiles if underlying pointer conversion is allowed. template Ptr& assign_with_const_cast(const Ptr& rhs) { _policy.delete_if_managing(_point); _point = const_cast(rhs.pointer()); if ( _point == 0 ) throw PtrInvalidCast(); _policy = P(_point,rhs.policy()); return *this; } // Assignment from any other type of Ptr with dynamic cast. // Compiles if underlying pointer conversion is allowed. template Ptr& assign_with_dynamic_cast(const Ptr& rhs) { _policy.delete_if_managing(_point); _point = dynamic_cast(rhs.pointer()); if ( rhs.pointer() != 0 ) if ( _point == 0 ) throw PtrInvalidCast(); _policy = P(_point,rhs.policy()); return *this; } // Copy constructor from the same type of Ptr. Ptr(const Ptr& rhs) : _point(rhs.pointer()), _policy( rhs.pointer(), rhs._policy ) { ++_count; } // Assignment from the same type of Ptr. Ptr& operator=(const Ptr& rhs) { if ( &rhs == this ) return *this; _policy.delete_if_managing(_point); _point = rhs.pointer(); _policy = P(_point, rhs._policy); return *this; } #else // Unsafe interface for compilers which do not allow // member templates. // Copy constructor. Ptr(const Ptr& rhs) : _point(rhs.pointer()), _policy( rhs.pointer(), (AbsPolicy&) rhs._policy ) { ++_count; } // Assignment. Ptr& operator=(const Ptr& rhs) { if ( &rhs == this ) return *this; _policy.delete_if_managing(_point); _point = rhs.pointer(); _policy = P(_point, (AbsPolicy&) rhs._policy); return *this; } // Construction from a TmpPtr. // This still does not allow direct construction from // another Ptr but does allow user to convert and construct: // Ptr px; // Ptr py = TmpPtr(px); // instead of Ptr py = px; Ptr(const TmpPtr& rhs) : _point( (T*) rhs.pointer() ), _policy( (T*) rhs.pointer(), rhs.policy() ) { ++_count; } // Unsafe assignment from a TmpPtr. // This allows assignment from any type of Ptr or bare pointer // via automatic conversion to TmpPtr. Ptr& operator=(const TmpPtr rhs) { _policy.delete_if_managing(_point); _point = (T*) rhs.pointer(); _policy = P(_point,rhs.policy()); return *this; } // Unsafe assignment from a TmpPtr. // This allows assignment from any type of Ptr or bare pointer // via automatic conversion to TmpPtr. Ptr& assign_with_const_cast(const TmpPtr rhs) { _policy.delete_if_managing(_point); _point = (T*) rhs.pointer(); _policy = P(_point,rhs.policy()); return *this; } // Unsafe assignment from a TmpPtr. // This allows assignment from any type of Ptr or bare pointer // via automatic conversion to TmpPtr. Ptr& assign_with_dynamic_cast(const TmpPtr rhs) { _policy.delete_if_managing(_point); _point = (T*) rhs.pointer(); _policy = P(_point,rhs.policy()); return *this; } // Provide automatic conversion to TmpPtr to enable the above // assignment. operator TmpPtr() const { return TmpPtr(_point,_policy); } #endif public: // methods // Assignment from a bare pointer of the same type. // This is needed so we can assign from a null pointer. // NT finds this to be ambiguous, so we add a method taking // an int argument. #ifndef NT_MSVCPP Ptr& operator=(T* rhs) { _policy.delete_if_managing(_point); _point = rhs; _policy = P(_point); return *this; } #else Ptr& operator=(int irhs) { assert( irhs == 0 ); T* rhs = 0; _policy.delete_if_managing(_point); _point = rhs; _policy = P(_point); return *this; } #endif // return the bare pointer T* pointer() const { if ( is_valid() ) return _point; else return 0; } // Return the policy. P& policy() const { #ifndef DEFECT_NO_MUTABLE return _policy; #else return (P&) _policy; #endif } // dereference T& operator*() const { if ( ! is_valid() ) throw PtrInvalidPointer(); return *pointer(); } // class member selection T* operator->() const { if ( ! is_valid() ) throw PtrInvalidPointer(); return pointer(); } // Conversion to const void*. operator const void*() const { if ( ! is_valid() ) return 0; return _point; } // Output stream with detailed information. void print(std::ostream& stream) { stream << "Ptr with address " << _point << " and policy " << _policy; } // Output stream like a bare pointer. friend std::ostream& operator<<(std::ostream& stream, const Ptr& rhs) { stream << rhs._point; return stream; } }; #ifdef NT_MSVCPP // The automatic conversion to const void* should mean the following // are not neccessary. But this is not so in MSVC++ 6.0. template bool operator<(const Ptr& p1, const Ptr& p2) { return p1.pointer() < p2.pointer(); } template bool operator>(const Ptr& p1, const Ptr& p2) { return p1.pointer() > p2.pointer(); } template bool operator<(const T1* p1, const Ptr& p2) { return p1 < p2.pointer(); } template bool operator>(const T1* p1, const Ptr& p2) { return p1 > p2.pointer(); } template bool operator<(const Ptr& p1, const T2* p2) { return p1.pointer() < p2; } template bool operator>(const Ptr& p1, const T2* p2) { return p1.pointer() > p2; } #endif #ifndef __xlC__ template int Ptr::_count = 0; #endif #endif