SharedPtr-cpp03/SmartPtr.h

206 lines
4.5 KiB
C++

#ifndef SMARTPTR_H
#define SMARTPTR_H
#include <map>
#include <string>
#include <stdexcept>
/**
* Simple shared pointer class with NO thread safety (not even the counter is thread-safe)
*/
template <typename T>
class SmartPtr
{
//Rule 1: tracker is always NULL when ptr == NULL
//Rule 2: ID is only assigned in constructors
typedef std::map<unsigned long,SmartPtr<T>*> IDMap;
typedef std::pair<unsigned long,SmartPtr<T>*> IDPair;
T* ptr;
IDMap *tracker; //track pointers to same object
unsigned long ID;
static unsigned long __IDCounter;
public:
typedef T element_type;
SmartPtr(const SmartPtr& other);
SmartPtr<T>& operator=(const SmartPtr& other);
SmartPtr(T* new_ptr = NULL);
T& operator*();
const T& operator*() const;
~SmartPtr();
unsigned long use_count() const;
operator bool();
T* get();
const T* const get() const;
T* release();
void reset(T* new_ptr = NULL);
inline bool isNull();
template <template <typename _T, typename = std::allocator<_T> > class Container>
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container);
};
template <typename T>
unsigned long SmartPtr<T>::__IDCounter = 0;
template<typename T>
template <template <typename _T, typename = std::allocator<_T> > class Container>
Container<T*> SmartPtr<T>::GetRawPtrContainer(const Container<SmartPtr<T> >& input_container)
{
Container<T*> container;
for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin();
it != input_container.end();
it++)
{
container.push_back(it->ptr);
}
return container;
}
template<typename T>
SmartPtr<T>::SmartPtr(const SmartPtr &other)
{
this->tracker = other.tracker;
this->ptr = other.ptr;
this->ID = __IDCounter++;
if(!isNull())
tracker->insert(IDPair(ID,this));
}
template<typename T>
SmartPtr<T> &SmartPtr<T>::operator=(const SmartPtr &other)
{
this->tracker = other.tracker;
this->ptr = other.ptr;
this->ID = __IDCounter++;
if(!isNull())
tracker->insert(IDPair(ID,this));
return *this;
}
template<typename T>
SmartPtr<T>::SmartPtr(T *new_ptr)
{
ptr = NULL;
tracker = NULL;
ID = __IDCounter++;
reset(new_ptr);
}
template<typename T>
T& SmartPtr<T>::operator*()
{
if(this->get() != NULL)
return *this->get();
else
throw std::runtime_error("Null pointer exception. Tried to dereference a NULL in SmartPtr");
}
template<typename T>
const T& SmartPtr<T>::operator*() const
{
if(this->get() != NULL)
return *this->get();
else
throw std::runtime_error("Null pointer exception. Tried to dereference a NULL in SmartPtr");
}
template<typename T>
SmartPtr<T>::~SmartPtr()
{
reset();
}
template<typename T>
unsigned long SmartPtr<T>::use_count() const
{
if(isNull())
return 0;
else
return tracker->size();
}
template<typename T>
SmartPtr<T>::operator bool()
{
return !isNull();
}
template<typename T>
T *SmartPtr<T>::get()
{
return ptr;
}
template<typename T>
const T * const SmartPtr<T>::get() const
{
return ptr;
}
template<typename T>
T *SmartPtr<T>::release()
{
T* ret_ptr = ptr;
if(!isNull()) {
IDMap* trackerHolder = tracker;
for(typename IDMap::iterator it = trackerHolder->begin(); it != trackerHolder->end(); it++)
{
it->second->ptr = NULL;
it->second->tracker = NULL;
}
delete trackerHolder;
}
return ret_ptr;
}
template<typename T>
void SmartPtr<T>::reset(T *new_ptr) {
if(!isNull())
{
//ptr and tracker are not NULL, guaranteed
if(tracker->size() == 1) //this is the last reference
{
delete ptr;
ptr = NULL;
delete tracker;
tracker = NULL;
}
else
{
tracker->erase(ID);
if(new_ptr != NULL)
{
tracker = new IDMap;
tracker->insert(IDPair(ID,this));
}
else
{
tracker = NULL;
ptr = NULL;
}
}
}
else //if this is NULL
{
if(new_ptr != NULL)
{
if(tracker == NULL) {
tracker = new IDMap;
tracker->insert(IDPair(ID,this));
ptr = new_ptr;
}
}
}
}
template<typename T>
bool SmartPtr<T>::isNull()
{
return (ptr == NULL);
}
#endif // SMARTPTR_H