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:
Post a Comment