#include <iostream>
// Представьте, что доступа к этопу коду мы не имеем. Физически, организационно
// или просто люди, которые его разрабатывали или поддерживали, давно отсуствуют.
// На самом деле, это не сильно отличается от первого предположения
class LegacyObj
{
public:
LegacyObj(int i):_i(new int(i)){}
~LegacyObj(){
clear();
}
LegacyObj(const LegacyObj& rhs){
clear();
_i = new int(*rhs._i);
}
LegacyObj& operator=(const LegacyObj& rhs){
// этот вызов явно лишний, но ничего с ним сделать не можем
clear();
// копируем наши "ресурсы"
_i = new int(*rhs._i);
// настоящие ковбои никогда не проверяют &rhs != this
return *this;
}
void clear(){
delete _i;
// _i = 0; - если бы еще обнулили этот указатель, это нам бы помогло при отладке
}
void print_me(){
std::cout << *_i << std::endl;
}
private:
// вместо int* могут быть любые ресурсы, требующие аллокации
int* _i;
};
// Какая-то обертка вокруг старого кода
// Версия с проверкой
class WrapperWithCheck
{
public:
WrapperWithCheck(int a, int b, int c):_a(a),_b(b),_c(c){}
WrapperWithCheck(const WrapperWithCheck& rhs):_a(rhs._a),_b(rhs._b),_c(rhs._c){}
WrapperWithCheck& operator=(const WrapperWithCheck& rhs){
if(&rhs == this)
return *this;
_a = rhs._a;
_b = rhs._b;
_c = rhs._c;
return *this;
}
void print_me(){
_a.print_me();
_b.print_me();
_c.print_me();
}
private:
LegacyObj _a;
LegacyObj _b;
LegacyObj _c;
};
// Версия без проверки
class WrapperWithoutCheck
{
public:
WrapperWithoutCheck(int a, int b, int c):_a(a),_b(b),_c(c){}
WrapperWithoutCheck(const WrapperWithoutCheck& rhs):_a(rhs._a),_b(rhs._b),_c(rhs._c){}
WrapperWithoutCheck& operator=(const WrapperWithoutCheck& rhs){
_a = rhs._a;
_b = rhs._b;
_c = rhs._c;
return *this;
}
void print_me(){
_a.print_me();
_b.print_me();
_c.print_me();
}
private:
LegacyObj _a;
LegacyObj _b;
LegacyObj _c;
};
int main() {
{
WrapperWithCheck wrapper_with_check(1, 2, 3);
WrapperWithCheck other_wrapper(5, 6, 7);
std::cout << "Object with check" << std::endl;
wrapper_with_check.print_me();
WrapperWithCheck& wrapper_ref = wrapper_with_check;
// присваивание другому объекту
other_wrapper = wrapper_with_check;
// присваивание себе
wrapper_with_check = wrapper_ref;
std::cout << "After assignment" << std::endl;
wrapper_with_check.print_me();
}
{
WrapperWithoutCheck wrapper_without_check(1, 2, 3);
WrapperWithoutCheck other_wrapper(5, 6, 7);
std::cout << "Object without check" << std::endl;
wrapper_without_check.print_me();
WrapperWithoutCheck& wrapper_ref = wrapper_without_check;
// присваивание другому объекту
other_wrapper = wrapper_without_check;
// присваиваем себе
wrapper_without_check = wrapper_ref;
std::cout << "After assignment" << std::endl;
// вывод здесь не определен
// если бы обнулили указатель в clear() - получили бы debug assert и release crash
wrapper_without_check.print_me();
}
return 0;
}