fork download
  1. #include <iostream>
  2.  
  3. // Представьте, что доступа к этопу коду мы не имеем. Физически, организационно
  4. // или просто люди, которые его разрабатывали или поддерживали, давно отсуствуют.
  5. // На самом деле, это не сильно отличается от первого предположения
  6. class LegacyObj
  7. {
  8. public:
  9. LegacyObj(int i):_i(new int(i)){}
  10.  
  11. ~LegacyObj(){
  12. clear();
  13. }
  14.  
  15. LegacyObj(const LegacyObj& rhs){
  16. clear();
  17. _i = new int(*rhs._i);
  18. }
  19.  
  20. LegacyObj& operator=(const LegacyObj& rhs){
  21.  
  22. // этот вызов явно лишний, но ничего с ним сделать не можем
  23. clear();
  24.  
  25. // копируем наши "ресурсы"
  26. _i = new int(*rhs._i);
  27.  
  28. // настоящие ковбои никогда не проверяют &rhs != this
  29. return *this;
  30. }
  31.  
  32. void clear(){
  33. delete _i;
  34. // _i = 0; - если бы еще обнулили этот указатель, это нам бы помогло при отладке
  35. }
  36.  
  37. void print_me(){
  38. std::cout << *_i << std::endl;
  39. }
  40.  
  41. private:
  42. // вместо int* могут быть любые ресурсы, требующие аллокации
  43. int* _i;
  44. };
  45.  
  46. // Какая-то обертка вокруг старого кода
  47.  
  48. // Версия с проверкой
  49. class WrapperWithCheck
  50. {
  51. public:
  52.  
  53. WrapperWithCheck(int a, int b, int c):_a(a),_b(b),_c(c){}
  54.  
  55. WrapperWithCheck(const WrapperWithCheck& rhs):_a(rhs._a),_b(rhs._b),_c(rhs._c){}
  56.  
  57. WrapperWithCheck& operator=(const WrapperWithCheck& rhs){
  58. if(&rhs == this)
  59. return *this;
  60.  
  61. _a = rhs._a;
  62. _b = rhs._b;
  63. _c = rhs._c;
  64. return *this;
  65. }
  66.  
  67. void print_me(){
  68. _a.print_me();
  69. _b.print_me();
  70. _c.print_me();
  71. }
  72.  
  73. private:
  74. LegacyObj _a;
  75. LegacyObj _b;
  76. LegacyObj _c;
  77. };
  78.  
  79.  
  80. // Версия без проверки
  81. class WrapperWithoutCheck
  82. {
  83. public:
  84.  
  85. WrapperWithoutCheck(int a, int b, int c):_a(a),_b(b),_c(c){}
  86.  
  87. WrapperWithoutCheck(const WrapperWithoutCheck& rhs):_a(rhs._a),_b(rhs._b),_c(rhs._c){}
  88.  
  89. WrapperWithoutCheck& operator=(const WrapperWithoutCheck& rhs){
  90. _a = rhs._a;
  91. _b = rhs._b;
  92. _c = rhs._c;
  93. return *this;
  94. }
  95.  
  96. void print_me(){
  97. _a.print_me();
  98. _b.print_me();
  99. _c.print_me();
  100. }
  101.  
  102. private:
  103. LegacyObj _a;
  104. LegacyObj _b;
  105. LegacyObj _c;
  106. };
  107.  
  108. int main() {
  109.  
  110. {
  111. WrapperWithCheck wrapper_with_check(1, 2, 3);
  112. WrapperWithCheck other_wrapper(5, 6, 7);
  113. std::cout << "Object with check" << std::endl;
  114. wrapper_with_check.print_me();
  115. WrapperWithCheck& wrapper_ref = wrapper_with_check;
  116.  
  117. // присваивание другому объекту
  118. other_wrapper = wrapper_with_check;
  119.  
  120. // присваивание себе
  121. wrapper_with_check = wrapper_ref;
  122. std::cout << "After assignment" << std::endl;
  123. wrapper_with_check.print_me();
  124. }
  125.  
  126. {
  127. WrapperWithoutCheck wrapper_without_check(1, 2, 3);
  128. WrapperWithoutCheck other_wrapper(5, 6, 7);
  129. std::cout << "Object without check" << std::endl;
  130. wrapper_without_check.print_me();
  131. WrapperWithoutCheck& wrapper_ref = wrapper_without_check;
  132.  
  133. // присваивание другому объекту
  134. other_wrapper = wrapper_without_check;
  135.  
  136. // присваиваем себе
  137. wrapper_without_check = wrapper_ref;
  138. std::cout << "After assignment" << std::endl;
  139. // вывод здесь не определен
  140. // если бы обнулили указатель в clear() - получили бы debug assert и release crash
  141. wrapper_without_check.print_me();
  142. }
  143. return 0;
  144. }
  145.  
Success #stdin #stdout 0s 3476KB
stdin
Standard input is empty
stdout
Object with check
1
2
3
After assignment
1
2
3
Object without check
1
2
3
After assignment
0
0
0