Monday, December 16, 2013

A simple C++ smart pointer class

Until I started using move semantics of C++11, I used this smart pointer class, which is template-based, heavily relies on operator overloading, and uses an instance counter:
template<typename T> class Ptr {
public:
	Ptr()                 : _ptr(NULL), _counter(NULL) { }
	Ptr(T *ptr)           : _ptr(NULL), _counter(NULL) { operator=(ptr); }
	Ptr(const Ptr& other) : _ptr(NULL), _counter(NULL) { operator=(other); }
	~Ptr() {
		if(_counter && !--(*_counter)) {
			delete _ptr;     _ptr = NULL;
			delete _counter; _counter = NULL;
		}
	}
	Ptr& operator=(T *ptr) {
		this->~Ptr();
		if(ptr) {
			_ptr = ptr; // take ownership
			_counter = new int(1); // start counter
		}
		return *this;
	}
	Ptr& operator=(const Ptr& other) {
		if(this != &other) {
			this->~Ptr();
			_ptr = other._ptr;
			_counter = other._counter;
			if(_counter) ++(*_counter);
		}
		return *this;
	}
	bool isNull() const         { return _ptr == NULL; }
	T& operator*()              { return *_ptr; }
	const T* operator->() const { return _ptr; }
	T* operator->()             { return _ptr; }
	operator T*() const         { return _ptr; }
private:
	T   *_ptr;
	int *_counter;
};
Example usage:
struct When {
	int month;
	int day;
};

Ptr<When> GetLunchTime()
{
	Ptr<When> ret = new When(); // alloc pointer to be owned
	ret->month = 12;
	ret->day = 16;
	return ret;
}

int main()
{
	Ptr<When> lunchTime = GetLunchTime();
	// ...
	// no need to delete lunchTime
	return 0;
}
It works fine, but with the implementation of move semantics – which is truly great –, it seems that I don’t need it anymore. So I’m publishing it here for historical reasons.

No comments: