Normal pointers and references to shared objects.
Sample
//Creates a new shared object (ref counted) X* pShared = new_shared_object<X>(); //Shares the object with pShared2 X* pShared2 = share_object(pShared); //Release the pShared reference release_shared_object(pShared); pShared = nullptr; //Release the pShared2 reference release_shared_object(pShared2); pShared2 = nullptr; //References: X& sharedRef = *new_shared_object<X>(); X& sharedRef2 = share_object(sharedRef); //(destructor for instance) release_shared_object(sharedRef); release_shared_object(sharedRef2);
Source Code: (scratch)
template<class T> struct AtomicHolder : public T { std::atomic<unsigned int> counter; AtomicHolder() { counter = 1; } template<class A1, class A2> AtomicHolder(A1&& a1, A2&& a2) : T(std::forward<A1>(a1), std::forward<A2>(a2)) { counter = 1; } }; template<class T> int is_shared_object(T *p) { if (!std::is_polymorphic<T>::value) { //we can't check using this method return -1; } return typeid(*p) == typeid(AtomicHolder<T>) ? 1 : 0; } template<class T> T* share_object(T* p) { assert(is_shared_object(p) != 0); AtomicHolder<T> *p2 = static_cast<AtomicHolder<T>*>(p); p2->counter++; return p; } template<class T> T& share_object(T& r) { return *share_object(&r); } template<class T> void release_shared_object(T* p) { if (p == nullptr) return; assert(is_shared_object(p) != 0); AtomicHolder<T> *p2 = static_cast<AtomicHolder<T>*>(p); if (p2->counter.fetch_add(-1) == 1) delete p2; } template<class T> void release_shared_object(T& r) { release_shared_object(&r); } template <class T> T* new_shared_object() //0..N arguments { T* p0 = new AtomicHolder<T>(); //I don't want to use dynamic_cast assert(static_cast<AtomicHolder<T>*>(static_cast<T*>(p0)) == p0); return p0; } template <class T, class A1, class A2> AtomicHolder<T>* new_shared_object(A1&& a1, A2&& a2) //0..N arguments { AtomicHolder<T>* p0 = new AtomicHolder<T>(std::forward<A1>(a1), std::forward<A2>(a2)); //I don't want to use dynamic_cast assert(static_cast<AtomicHolder<T>*>(static_cast<T*>(p0)) == p0); return p0; }
Sample
using namespace std; struct X { X() { std::cout << "X" << std::endl; } virtual ~X() { std::cout << "~X" << std::endl; } }; int _tmain(int argc, _TCHAR* argv[]) { //X *pNotShared = new X; //X* pSharedWrong = share_object(pNotShared); //error X* pShared = new_shared_object<X>(); X* pShared2 = share_object(pShared); release_shared_object(pShared); release_shared_object(pShared2); X& sharedRef = *new_shared_object<X>(); X& sharedRef2 = share_object(sharedRef); release_shared_object(sharedRef); release_shared_object(sharedRef2); return 0; }
Sample2:
struct Point { int m_x; int m_y; Point(int x, int y) : m_x(x), m_y(y) { std::cout << "Point(" <<m_x << ", " << m_y << ")" << std::endl; } ~Point() { std::cout << "~Point(" <<m_x << ", " << m_y << ")" << std::endl; } }; struct Line { Point& m_start; Point& m_end; Line(Point& start, Point& end) : m_start(share_object(start)), m_end(share_object(end)) { std::cout << "Line" << std::endl; } ~Line() { release_shared_object(m_start); release_shared_object(m_end); std::cout << "~Line" << std::endl; } }; template<class T> struct SmartPtr { T *m_p; SmartPtr(AtomicHolder<T> *p) { m_p = p; } ~SmartPtr() { release_shared_object(m_p); } operator T*() { return m_p; } T * get() { return m_p; } }; int _tmain(int argc, _TCHAR* argv[]) { { Line *pline = nullptr; { SmartPtr<Point> pt1(new_shared_object<Point>(0,0)); SmartPtr<Point> pt2(new_shared_object<Point>(1,1)); pline = new Line(*pt1.get(), *pt2.get()); } Line *pline2 = nullptr; { SmartPtr<Point> pt3(new_shared_object<Point>(1,0)); pline2 = new Line(pline->m_end, *pt3.get()); } delete pline; delete pline2; } return 0; }
Output:
Point(0, 0) Point(1, 1) Line Point(1, 0) Line ~Point(0, 0) ~Line ~Point(1, 1) ~Point(1, 0) ~Line
See also: shared_ptr