Listing 1: Header file for smart pointers implementation
// Copyright (c) 1996-1997 Vladimir Batov // // Permission to use, copy, modify, distribute and sell this // software and its documentation for any purpose is hereby // granted without fee, provided that the above copyright notice // appear in all copies and that both that copyright notice and // this permission notice appear in supporting documentation. // I make no representations about the suitability of this software // for any purpose. It is provided "as is" without express or // implied warranty. // Handle<T> requires T class to have T::T() and // T::T(const T&) constructors. #ifndef BATOV_HANDLE_H #define BATOV_HANDLE_H typedef unsigned int uint; class HandleError { public: ~HandleError () {} HandleError () : _error(_allocate()) {} HandleError (uint err) : _error(err) {} operator uint () const { return _error; } bool operator== (const HandleError& e) const { return _error == e._error; } static HandleError no_error; static HandleError unknown; private: uint _error; uint _allocate(); }; template<class T/*, class Allocator = MemoryAllocator When supported*/> class Handle { public: typedef HandleError Error; private: class Counted { public: ~Counted () {} Counted (); Counted (const T&); void dismiss () { if (!--_num_references) delete this; } void use () { ++_num_references; } operator T& () { return _instance; } operator const T& () const { return _instance; } operator T* () { return &_instance; } operator const T* () const { return &_instance; } T* operator-> () { return &_instance; } const T* operator-> () const { return &_instance; } // Possible memory optimization. See [6]. // void* operator new (size_t) // { return _allocator.allocate(); } // void operator delete (void* storage) // { _allocator.deallocate(storage); } bool is_shared () const { return 1 < _num_references ? true : false; } bool is_error () const { return _error ? true : false; } Error get_error () const { return _error; } void set_error (Error); private: T _instance; uint _num_references : 16; // Reference counter. // (<=65535 looks enough) uint _error : 16; // Error conditions flag. // (<=65535) // Possible memory optimization. See [6]. // static MemoryAllocator _allocator; }; public: ~Handle (); Handle (); Handle (const T&); Handle (const T*); Handle (const Handle<T>&); operator T& () { return _counted->operator T&(); } operator T* () { return _counted->operator T*(); } operator const T& () const { return _counted->operator T&(); } operator const T* () const { return _counted->operator T*(); } const T* operator-> () const { return _counted->operator ->(); } T* operator-> () { return _counted->operator ->(); } Handle<T>& operator = (const T&); Handle<T>& operator = (const T*); Handle<T>& operator = (const Handle<T>&); static Handle<T> error (Error =Error::unknown); void set_error (Error =Error::unknown); Error get_error () const { return _counted->get_error(); } bool is_error () const { return _counted-> is_error(); } bool is_shared () const { return _counted->is_shared(); } Handle<T> duplicate () const; // Convenience method to create // a copy of a "T-Handle<T>" pair. private: Counted* _counted; // User has NO ACCESS TO THE ADDRESS OF A HANDLE instance // as such access bypasses reference counter mechanism. // User is forced to pass it by value (Handle) that is // supervised by the mechanism. Handle<T>* operator& (); // Not defined to prevent usage. }; template<class T> inline Handle<T>::Counted::Counted() : _num_references(0), _error(Error::no_error), _instance() { // Preferred form of T instance creation. } template<class T> inline Handle<T>::Counted::Counted(const T& from) : _num_references(0), _error(Error::no_error), _instance(from) { // Should be avoided as an internal copy of 'from' // is created. } template<class T> inline void Handle<T>::Counted::set_error(Error err) { _error = err < Error::unknown ? err : Error::unknown; } template<class T> inline Handle<T> Handle<T>::error(Error num) { Handle<T> h; h.set_error(num); return h; } template<class T> inline void Handle<T>::set_error(Error err) { _counted->set_error(err); } template<class T> inline Handle<T>::~Handle() { _counted->dismiss(); } template<class T> inline Handle<T>::Handle() : _counted(new Counted()) { _counted->use(); } template<class T> inline Handle<T>::Handle(const T& copy) : _counted(new Counted(copy)) { _counted->use(); } template<class T> inline Handle<T>::Handle(const T* copy) : _counted(copy ? new Counted(*copy) : new Counted()) { _counted->use(); } template<class T> inline Handle<T>::Handle(const Handle<T>& ref) : _counted(ref._counted) { _counted->use(); } template<class T> inline Handle<T>& Handle<T>::operator=(const T& src) //8. { if (*this != &src) { _counted->dismiss(); _counted = new Counted(src); _counted->use(); } return *this; } template<class T> inline Handle<T>& Handle<T>::operator=(const T* src) //8. { if (*this != src) { _counted->dismiss(); _counted = src ? new Counted(*src) : new Counted(); _counted->use(); } return *this; } template<class T> inline Handle<T>& Handle<T>::operator=(const Handle<T>& src) { if (this->_counted != src._counted) { _counted->dismiss(); _counted = src._counted; _counted->use(); } return *this; } template<class T> inline Handle<T> Handle<T>::duplicate() const { return Handle<T>(operator->()); } #endif // BATOV_HANDLE_H // End of File