fork download
  1. #include <iostream>
  2. using namespace std;
  3.  
  4.  
  5. template<typename TDerived>
  6. class ReferenceCounting {
  7. public:
  8. typedef TDerived Derived ;
  9.  
  10. ReferenceCounting() : m_ref(0) { }
  11. ~ReferenceCounting() {std::cout <<" RC:DTOR" <<std::endl; }
  12.  
  13. unsigned long int addRef(){
  14. ++m_ref;
  15. std::cout << "RC::addRef: " << m_ref << std::endl;
  16. return m_ref;
  17. }
  18. void release(){
  19. --m_ref;
  20. std::cout << "RC::release: " << m_ref << std::endl;
  21. if(!m_ref){
  22. std::cout << "RC::delete" << std::endl;
  23. delete static_cast<Derived const *>(this);
  24. }
  25. }
  26. unsigned long int getRefCount(){return m_ref;}
  27.  
  28. private:
  29. mutable unsigned long int m_ref; // Mutable to be changeable also for const objects!
  30. };
  31.  
  32. template<typename T>
  33. inline long intrusive_ptr_add_ref(T* t) {
  34. return t->addRef();
  35. }
  36. template<typename T>
  37. inline void intrusive_ptr_release(T* t) {
  38. t->release();
  39. }
  40.  
  41. template<typename T>
  42. class IntrusivePtr {
  43. public:
  44. IntrusivePtr() : m_p(nullptr) { }
  45. explicit IntrusivePtr(T* p) : m_p(p) {
  46. if(p) intrusive_ptr_add_ref(static_cast<typename T::RCBaseType *>(m_p));
  47. }
  48.  
  49. IntrusivePtr(const IntrusivePtr & rhs) : m_p(rhs.m_p) {
  50. if(m_p) intrusive_ptr_add_ref(static_cast<typename T::RCBaseType *>(m_p));
  51. }
  52.  
  53. template<typename Y>
  54. IntrusivePtr(const IntrusivePtr<Y>& rhs) {
  55. // for IntrusivePtr<const T> copy construct somehow?
  56. }
  57.  
  58. ~IntrusivePtr() {
  59. if(m_p) intrusive_ptr_release(static_cast<typename T::RCBaseType *>(m_p));
  60. }
  61.  
  62.  
  63. // We want to assign the intrusive ptr to this class
  64. // m_p points to A, rhs->m_p points to B
  65. // This means, decrease ref count of current object A, an set m_p=rhs->m_p
  66. // and increase ref count of rhs resource. This can by:
  67. // Copy and swap idiom, call by value to copy the IntrusivePtr (ref count of B increments)
  68. // swap this resource pointer into the local temporary rhs (only pointer swap)
  69. // deleting the local rhs at end of function decrements ref count of initial resource A
  70. IntrusivePtr& operator=(IntrusivePtr rhs) {
  71. rhs.swap(*this); // swaps the resource pointers
  72. return *this; // delete rhs-> which decrements correctly our initial resource A!
  73. }
  74.  
  75. // Reset the IntrusivePtr to some other resource B,
  76. // meaning decrementing our resource A and setting the new pointer to B
  77. // and incrementing B
  78. // Can also take a nullptr!, making it not default argument because avoiding syntax mistakes with release()
  79. // which does a complete different thing (takes off the IntrusivePtr)
  80. void reset(T* p) {
  81. // Make temporary intrusive pointer for *p (incrementing ref count B)
  82. // swapping pointers with our resource A, and deleting temporary, decrement A
  83. IntrusivePtr(p).swap(*this);
  84. }
  85.  
  86. // Release a IntrusivePtr from managing the shared resource
  87. // Decrements ref count of this resource A but without deleting it!
  88. T* release() {
  89.  
  90. T* p = m_p;
  91. m_p = nullptr;
  92.  
  93. return p;
  94.  
  95. }
  96.  
  97. // Get the underlying pointer
  98. T* get() const { return m_p; }
  99.  
  100. // Implicit cast to T*
  101. operator T*() const { return m_p; }
  102. // Implicit cast to T&
  103. operator T&() const { return *m_p; }
  104.  
  105. T* operator->() const { return m_p; }
  106.  
  107. void swap(IntrusivePtr& rhs) {
  108. std::swap(m_p, rhs.m_p);
  109. }
  110. private:
  111. T* m_p;
  112. };
  113.  
  114.  
  115. class A : public ReferenceCounting<A>{
  116. public:
  117.  
  118. typedef ReferenceCounting<A> RCBaseType;
  119. A(){}
  120. A(A&c){std::cout << "A::copy construct" << std::endl;}
  121. A& operator=(A&c){std::cout << "A::copy assign" << std::endl;}
  122. ~A(){
  123. std::cout << "A::DTOR: " <<this << std::endl;
  124. }
  125.  
  126. int foo(){return i[10000];}
  127.  
  128. int i[10001];
  129. };
  130.  
  131. int main(){
  132. std::cout << "TEst 1 "<< std::endl;
  133. {
  134. A *a = new A();
  135. IntrusivePtr<A> p2 (a);
  136. std::cout << "Create Local " <<p2<< std::endl;
  137. {
  138. std::cout << "Create IntrPtr" << std::endl;
  139. IntrusivePtr<A> p(p2);
  140. // Copy object
  141. A c(p);
  142. std::cout << "Ref count of copied obj:" << c.getRefCount() << std::endl;
  143.  
  144. A b = *a;
  145. std::cout << "Ref count of copied obj:" << b.getRefCount() << std::endl;
  146. {
  147. std::cout << "Create IntrPtr2" << std::endl;
  148. // IntrusivePtr<A const> p1(p);
  149.  
  150. }
  151. }
  152. std::cout << "Create Ref" << std::endl;
  153. std::cout << p2->foo() << std::endl;
  154. }
  155.  
  156.  
  157.  
  158. }
  159.  
Success #stdin #stdout 0s 3476KB
stdin
Standard input is empty
stdout
TEst 1 
RC::addRef: 1
Create Local 0x8a5d008
Create IntrPtr
RC::addRef: 2
A::copy construct
Ref count of copied obj:0
A::copy construct
Ref count of copied obj:0
Create IntrPtr2
A::DTOR: 0xbfca6c88
 RC:DTOR
A::DTOR: 0xbfc9d040
 RC:DTOR
RC::release: 1
Create Ref
0
RC::release: 0
RC::delete
A::DTOR: 0x8a5d008
 RC:DTOR