shared_ptr brings convenience to memory management but it also comes at a cost. It blocks the use of covariant return types. Also it makes interfacing with other environments difficult, for instance if you wanted to make a C wrapper around your C++ code. shared_ptr keeps an internal reference count of the object, but if we switch that around and put the reference count inside of the object we could choose when to use smart pointers without losing a consistent count. That way we can keep our interfaces clean of smart pointers, but use them internally to get their benefit. Without further ado I present refcountptr with the disclaimer that I wrote it for this post, I’ve only done minimal testing.
refcountptr:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#pragma once template<class T> class refcountptr { public: ~refcountptr() { if (this->px) { this->px->release(); } } refcountptr() : px(0) {} template<class Y> explicit refcountptr( Y * p ): px( p ) { if (this->px) { this->px->retain(); } } template<class Y> refcountptr( refcountptr<Y> const & r ) : px( r.px ) { if (px) { this->px->retain(); } } refcountptr & operator=( refcountptr const & r ) { swap(r.px); return *this; } template<class Y> refcountptr & operator=(refcountptr<Y> const & r) { swap(r.px); return *this; } T& operator* () const { return *px; } T * operator-> () const { return px; } T * get() const { return px; } private: template<class Y> void swap(Y* newPtr) { T* oldPx = px; px = newPtr; if (px) { px->retain(); } if (oldPx) { oldPx->release(); } } T * px; }; |
example of usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include "refcountptr.hpp" #include <iostream> class Foo { public: Foo(int x) : _refCount(0), _x(x) {} ~Foo() { std::cout << "dealloc!" << std::endl; } void retain() { _refCount += 1; } void release() { _refCount -= 1; if (_refCount<=0) { delete this; } } int getX() { return _x; } private: int _refCount; int _x; }; int main(int argc, char *argv[]) { refcountptr<Foo> bar; { refcountptr<Foo> foo(new Foo(1234)); bar = foo; std::cout << foo->getX() << std::endl; } std::cout << bar->getX() << std::endl; return 0; } |