ok, here's another variation:
Code:
template <class type, type set = type()>
struct invalid {
invalid()
: value(set) {
}
inline const type & operator () (void) {
return value;
}
inline operator const type & (void) {
return value;
}
protected:
type value;
};
template <class type, class unloader, class null_type = invalid<type, (type)0> >
class ref_handle {
public:
inline type get (void) {
return m_pointer;
}
ref_handle & assign(ref_handle & rhs) {
rhs.inc_ref(); /* works even if rhs == *this || rhs.m_refs == m_refs */
dec_ref();
m_pointer = rhs.m_pointer;
m_refs = rhs.m_refs;
return *this;
}
inline ref_handle & operator = (ref_handle & rhs) {
return assign(rhs);
}
inline ref_handle & operator = (const ref_handle & rhs) { /* std::containers might expect this */
return assign(const_cast<ref_handle&>(rhs));
}
ref_handle & assign(type data) {
dec_ref();
if(data != m_null) {
try {
m_refs = new size_t(1);
} catch(std::bad_alloc & exception) { /* wow, must be serious */
m_unload(data);
throw exception;
}
m_pointer = data;
}
return *this;
}
ref_handle & assign(type data, unloader new_unloader) {
assign(data);
m_unload = new_unloader;
return *this;
}
inline ref_handle & operator = (type data) {
return assign(data);
}
ref_handle(const ref_handle & rhs)
: m_pointer(m_null), m_refs(NULL) {
*this = rhs;
}
ref_handle(type data)
: m_pointer(m_null), m_refs(NULL) {
*this = data;
}
ref_handle(type data, unloader function)
: m_pointer(m_null), m_refs(NULL), m_unload(function) {
*this = data;
}
ref_handle(void)
: m_pointer(m_null), m_refs(NULL) {
}
virtual ~ref_handle(void) {
dec_ref();
}
protected:
void dec_ref(void) {
if(m_refs != NULL) {
if(--(*m_refs) == 0) {
m_unload(m_pointer);
delete m_refs;
}
m_pointer = m_null;
m_refs = NULL;
}
}
void inc_ref(void) {
if(m_refs != NULL) {
++(*m_refs);
}
}
protected:
type m_pointer;
unloader m_unload;
null_type m_null;
size_t * m_refs;
};
template < class type, class unloader = delete_ptr<type> >
class ref_ptr : ref_handle < type*, unloader, invalid<type*, (type*)0> > {
public:
inline type * operator -> (void) {
return m_pointer;
}
inline type & operator * (void) {
return *m_pointer;
}
inline ref_ptr & operator = (ref_ptr & rhs) {
assign(rhs);
return *this;
}
inline ref_ptr & operator = (const ref_ptr & rhs) { /* std::containers might expect this */
assign(const_cast<ref_ptr&>(rhs));
return *this;
}
inline ref_ptr & operator = (type * data) {
assign(data);
return *this;
}
ref_ptr(const ref_ptr & rhs)
: ref_handle< type*, unloader, invalid<type*, (type*)0> >(rhs) {
}
ref_ptr(type * data)
: ref_handle< type*, unloader, invalid<type*, (type*)0> >(data) {
}
ref_ptr(type * data, unloader function)
: ref_handle< type*, unloader, invalid<type*, (type*)0> >(data, function) {
}
ref_ptr(void)
: ref_handle< type*, unloader, invalid<type*, (type*)0> >() {
}
};
the ref_handle template is for doing things like:
Code:
struct MsHandleCloser {
void operator()(HANDLE handle) {
CloseHandle(handle);
}
};
typedef ref_handle < HANDLE, MsHandleCloser, invalid<HANDLE, INVALID_HANDLE_VALUE> > MsHandle;
[edit]
the catch block had a bug - it freed 'm_pointer' instead of 'data'.
[/edit]