I've written a linked-list version of something like shared_ptr
, which gets destroyed when the last copy of a pointer is destroyed.
Aside from the thread-unsafety, is it a fine implementation? Anything I could improve?
Also, what's the best way to extend it to make it work with HANDLE
s, etc., without repeating (or limiting) myself unnecessarily, while avoiding excess verbosity (e.g. auto_<HANDLE, custom_deallocator<HANDLE> >
is considered too verbose)?
template<typename T>
class auto_
{
T *pValue;
mutable const auto_<T> *pPrev, *pNext;
public:
auto_() : pValue(new T()), pPrev(NULL), pNext(NULL) { }
auto_(T *pValue) : pValue(pValue), pPrev(NULL), pNext(NULL) { }
auto_(const T &v) : pValue(new T(v)), pPrev(NULL), pNext(NULL) { }
auto_(const auto_<T> &o) : pValue(o.pValue), pPrev(&o), pNext(NULL) { o.pNext = this; }
virtual ~auto_()
{
const auto_<T> *const pPrev = this->pPrev, *const pNext = this->pNext;
if (pPrev != NULL) { pPrev->pNext = pNext; }
if (pNext != NULL) { pNext->pPrev = pPrev; }
if (pPrev == NULL && pNext == NULL) { delete this->pValue; }
this->pPrev = this->pNext = NULL;
this->pValue = NULL;
}
auto_<T>& operator=(const auto_<T>& other)
{
if (this != &other)
{
this->~auto_();
this->pValue = other.pValue;
this->pPrev = &other;
this->pNext = other.pNext;
if (other.pNext != NULL) { other.pNext->pPrev = this; }
other.pNext = this;
}
return *this;
}
operator T&() /*also const version*/ { return *this->pValue; }
operator T*() /*also const version*/ { return this->pValue; }
T* operator->() /*also const version*/ { return this->pValue; }
T& operator *() /*also const version*/ { return *this->pValue; }
};
Sample usage:
template<typename T>
T recurse(T value, int depth)
{
if (depth > 0) { T result = recurse(value, depth - 1); return result; }
else { return value; }
}
auto_<int> test()
{
printf("Value: %d\n", *recurse(auto_<int>(10), 3));
auto_<int> p1 = recurse<auto_<int> >(5, 3);
printf("Value: %d\n", *p1);
auto_<int> p2 = 3;
p1 = p2;
p2 = p1;
return p2;
}
shared_ptr
has one big advantage over your class. It is thread safe, which means that more than one thread can share the object being pointed to. Yours cannot do that. Being able to do that incurs significant overhead when fiddling with the reference count. \$\endgroup\$