Whenever I'm writing old-school C-style memory management code in C++ these days (i.e. raw pointers, not 100% RAII, no "smart" anything), I now use a template like this that asserts when you forget to clean up properly. It also greatly helps to annotate which raw pointers are users of an object, and which raw pointer is the actual owner of an object:
template<class T> struct Owner
{
~Owner() { ASSERTMSG(p == 0, "Leak detected"); }
void Release() { if(p) p->Release(); p = 0; }
T* Relinquish() { T* copy = p; p = 0; return copy; }
explicit Owner(T* data=0) : p(data) {}
Owner(const Owner& o) : p(o.p) {o.p=0;}
Owner<T>& operator=(const Owner& o) { ASSERTMSG(p == 0, "Leak detected"); p = o.p; o.p=0; return *this; }
Owner<T>& operator=(T* data) { ASSERTMSG(p == 0, "Leak detected"); p = data; return *this; }
operator Ptr<T>() const { return p; }
T* operator->() const { ASSERT(p, "null dereference"); return p; }
T& operator *() const { ASSERT(p, "null dereference"); return *p; }
operator bool() const { return !!p; }
T* Raw() const { return p; }
private:
mutable T* p;
};
//e.g.
struct Foo {
//int* m_A;//bad
//int* m_B;//bad
Owner<int> m_A;
Ptr<int> m_B;
Foo() { m_A = new int; }
~Foo() { delete m_A.relinquish(); }// if you forget to write this part, you'll get an assertion failure!
};
And I use this one for non-owning pointers to ensure that uninitialized pointer bugs don't ever happen:
template<class T> struct Ptr
{
Ptr(T* data=0) : p(data) {}
operator T*() const { return p; }
T* operator->() const { ASSERTMSG(p, "null dereference"); return p; }
T& operator *() const { ASSERTMSG(p, "null dereference"); return *p; }
operator bool() const { return !!p; }
T* Raw() const { return p; }
private:
T* p;
};
In optimized builds there's basically no overhead compared to actually using raw pointers, but in development builds they catch all sorts of bugs.
I've had similar templates forced onto me during several game projects in the past and I really didn't like them at the time... however, 5 years of fixing stupid bugs later and now I'm converted and will recommend this practice to others :D
I haven't looked into it fully, but I believe that the C++ Core Guidelines project supplies similar templates to mine (except probably much more robust!).