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