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