fork download
  1.  
  2.  
  3. #include <cassert>
  4. #include <cstddef>
  5. #include <atomic>
  6.  
  7. #undef dVIEWNUMBERS
  8.  
  9. #ifdef dVIEWNUMBERS
  10. #ifndef _IOSTREAM_
  11. #error include <iostream> first
  12. #endif
  13. #undef dVIEWNUMBERS
  14. #define dVIEWNUMBERS \
  15.   std::cout << "instances = " << Instances() << std::endl;
  16. #else
  17. #define dVIEWNUMBERS
  18. #endif
  19.  
  20. namespace tools{
  21.  
  22. // счетчик созданных экземпляров класса
  23. template<class T> class Copies
  24. {
  25. typedef std::atomic<size_t>
  26. count_t;
  27. public:
  28.  
  29. ~Copies()
  30. {
  31. // количество вызванных деструкторов больше,
  32. // чем количество предшествующих им конструкторов
  33. // (возможная причина такой неисправности -
  34. // запуск диструктора ресурса в многопоточной среде)
  35. assert( NumInstances() > 0 &&
  36. "ERROR: DESTRUCTOR CALLED WITHOUT CONSTRUCTOR" );
  37.  
  38. --NumInstances();
  39. dVIEWNUMBERS;
  40. }
  41.  
  42. Copies() { ++NumInstances(); dVIEWNUMBERS; }
  43. Copies(const Copies&) { ++NumInstances(); dVIEWNUMBERS; }
  44. Copies(Copies&&) { ++NumInstances(); dVIEWNUMBERS; }
  45.  
  46. static size_t Instances() { return NumInstances(); }
  47. private:
  48. static count_t& NumInstances()
  49. { static count_t n(0); return n; }
  50. };
  51.  
  52. }// namespace tools
  53.  
  54. //--------------------------------------------------------------------------------------------------
  55. //--------------------------------------------------------------------------------------------------
  56. //--------------------------------------------------------------------------------------------------
  57. //--------------------------------------------------------------------------------------------------
  58. //--------------------------------------------------------------------------------------------------
  59. //--------------------------------------------------------------------------------------------------
  60. //--------------------------------------------------------------------------------------------------
  61. //--------------------------------------------------------------------------------------------------
  62.  
  63. #include <iostream>
  64.  
  65. using namespace std;
  66.  
  67. template <class T>
  68. class Pointer
  69. {
  70. T *p;
  71. int counter;
  72. Pointer *k;
  73. public:
  74. Pointer(T *_p) : p(_p),counter(1),k(NULL)
  75. {}
  76. ~Pointer()
  77. {
  78. if (k) (k->counter)--;
  79. counter--;
  80. if(!counter && !k) delete p;
  81. }
  82. Pointer(Pointer &rhs)
  83. {
  84. rhs.counter++;
  85. counter = 1;
  86. k = &rhs;
  87. p = rhs.p;
  88. }
  89.  
  90. T* operator->() { return p; }
  91.  
  92. int users()const { return counter; }
  93. };
  94.  
  95. //--------------------------------------------------------------------------------------------------
  96. //--------------------------------------------------------------------------------------------------
  97. //--------------------------------------------------------------------------------------------------
  98. //--------------------------------------------------------------------------------------------------
  99. //--------------------------------------------------------------------------------------------------
  100. //--------------------------------------------------------------------------------------------------
  101. //--------------------------------------------------------------------------------------------------
  102. //--------------------------------------------------------------------------------------------------
  103.  
  104. struct ICat
  105. {
  106. // <--- отсутствует виртуальный диструктор
  107. // однако несмотря на это
  108. // смарт-поинтер должен суметь
  109. // позвать диструктор наследника
  110.  
  111. // --- виртуальную функцию задействуем
  112. // что бы проверить ресурс смарт-поинтера на
  113. // консистентность
  114. // в случае невалидного указателя на vtbl
  115. // скорее всего получим краш времени выполнения
  116. virtual void foo()const=0;
  117. };
  118.  
  119. class Cat : public ICat, public tools::Copies<ICat>
  120. {
  121. public:
  122. Cat() { cout << "ctor Cat " << this << endl; }
  123. Cat(const Cat&) { cout << "copy Cat " << this << endl; }
  124. Cat(Cat&&) { cout << "move Cat " << this << endl; }
  125. ~Cat() {cout << "dtor Cat " << this << endl; }
  126. virtual void foo()const { std::cout <<"cat\n"; }
  127. };
  128.  
  129.  
  130. int main()
  131. {
  132. std::cout << "hello, world\n";
  133.  
  134. {
  135. // --- тест на конкретный тип ресурса
  136.  
  137. Pointer<Cat> p1(new Cat);
  138. assert(p1.users()==1 && "ERROR: INVALID COUNTER" );
  139.  
  140. Pointer<Cat> p2 = p1;
  141. assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
  142. assert(p2.users()==2 && "ERROR: INVALID COUNTER" );
  143.  
  144. assert(Cat::Instances()==1 && "LOGIC ERROR");
  145.  
  146.  
  147. p1->foo();
  148. p2->foo();
  149.  
  150. Pointer<Cat> p3(new Cat);
  151. assert(p3.users()==1 && "ERROR: INVALID COUNTER" );
  152. Pointer<Cat> p4 = p3;
  153.  
  154. assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
  155. assert(p2.users()==2 && "ERROR: INVALID COUNTER" );
  156. assert(p3.users()==2 && "ERROR: INVALID COUNTER" );
  157. assert(p4.users()==2 && "ERROR: INVALID COUNTER" );
  158.  
  159. assert(Cat::Instances()==2 && "LOGIC ERROR");
  160.  
  161. p3->foo();
  162. p4->foo();
  163. }
  164. assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
  165. {
  166. // --- тест работы с интерфейсом
  167.  
  168. Pointer<ICat> p1(new Cat);
  169. Pointer<ICat> p2 = p1;
  170.  
  171. assert(Cat::Instances()==1 && "LOGIC ERROR");
  172.  
  173. p1->foo();
  174. p2->foo();
  175.  
  176. Pointer<Cat> p3(new Cat);
  177. Pointer<Cat> p4 = p3;
  178.  
  179. assert(Cat::Instances()==2 && "LOGIC ERROR");
  180.  
  181. p3->foo();
  182. p4->foo();
  183. }
  184. assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
  185. }
  186.  
Runtime error #stdin #stdout #stderr 0s 3460KB
stdin
Standard input is empty
stdout
hello, world
ctor Cat 0x9291a10
stderr
prog: prog.cpp:142: int main(): Assertion `p2.users()==2 && "ERROR: INVALID COUNTER"' failed.