Before you say anything: Due to project constraints, we cannot use Boost and we cannot use C++11 (yet; perhaps this will change some day).
The fact that I was unable to use smart pointers was nagging on me for some time, so I decided to cough up my own implementation, and it was surprisingly simple. So, I'd like you to have a look at it. Btw. I decided to use a linked list instead of a ref-counter to avoid new
ing counters.
I ran some unit tests and couldn't find a problem. Perhaps you can suggest improvements?
Here is my SharedPtr.h
:
#ifndef __NET_UTIL_SHARED_PTR_H__
#define __NET_UTIL_SHARED_PTR_H__
#include <stddef.h>
// since we cannot use boost nor C++11, nor TR1, we have to reinvent the wheel, sigh
namespace net {
namespace util {
class SharedPtrBase {
private:
mutable SharedPtrBase const* left;
mutable SharedPtrBase const* right;
protected:
SharedPtrBase();
SharedPtrBase(SharedPtrBase const& from);
~SharedPtrBase();
void leave() const; // Note: leaving is idempotent
void join(SharedPtrBase const* where) const;
void assertWrapper(bool) const;
public:
bool isSingleton() const;
};
template <typename T> struct Deallocator {
private:
bool doDelete; // not const to be def. assignable
public:
// Implicit Constructor on purpose!
Deallocator(bool doDelete = true) : doDelete(doDelete) {}
bool willDelete() const {
return doDelete;
}
void operator()(T* t) const {
if (doDelete)
delete t;
}
};
template <typename T, typename Delete = Deallocator<T> >
class SharedPtr : private SharedPtrBase {
private:
Delete del;
T* ptr;
void drop() {
if (ptr && isSingleton()) {
del(ptr);
ptr = NULL;
}
leave();
}
public:
// SharedPtr(p,false) will not delete the pointer! Useful for Stackobjects!
explicit SharedPtr(T* ptr = NULL, Delete del = Delete())
: SharedPtrBase(), del(del), ptr(ptr) {
}
SharedPtr(SharedPtr const& from)
: SharedPtrBase(from), del(from.del), ptr(from.ptr) {
}
~SharedPtr() {
drop();
}
SharedPtr& operator=(SharedPtr const& from) {
if (&from != this) {
drop();
del = from.del;
ptr = from.ptr;
join(&from);
}
return *this;
}
bool operator==(SharedPtr const& with) const {
return ptr == with.ptr;
}
bool operator==(T* with) const {
return ptr == with;
}
bool operator<(SharedPtr const& with) const {
return ptr < with.ptr;
}
bool operator<(T* with) const {
return ptr < with;
}
T& operator*() const {
return *operator->();
}
T* operator->() const {
assertWrapper(ptr);
return ptr;
}
//T* release() {
// leave();
// T* const p = ptr;
// ptr = NULL;
// return p;
//}
};
}
}
#endif
And my SharedPtr.cpp
:
#include "util/SharedPtr.h"
#include <assert.h>
namespace net {
namespace util {
SharedPtrBase::SharedPtrBase()
: left(this), right(this) {
}
SharedPtrBase::SharedPtrBase(SharedPtrBase const& from)
: left(this), right(this) {
join(&from);
}
SharedPtrBase::~SharedPtrBase() {
leave();
}
// Note: leaving is idempotent.
// Try as much as you like, you will never leave yourself.
void SharedPtrBase::leave() const {
left->right = right;
right->left = left;
}
void SharedPtrBase::join(SharedPtrBase const* where) const {
assert(where);
leave();
assert(where->left && where->right);
left = where->left;
left->right = this;
right = where;
right->left = this;
}
void SharedPtrBase::assertWrapper(bool condition) const {
assert(condition);
}
bool SharedPtrBase::isSingleton() const {
return left == this;
}
}
}
reinvent-the-wheel
tag! – bitmask Nov 26 '11 at 23:05__NET_UTIL_SHARED_PTR_H__
is reserved for the implementation. – Loki Astari Nov 27 '11 at 2:23