Ответ
Компилятор C++ автоматически генерирует оператор присваивания копированием (operator=), если он не объявлен явно и в классе нет полей, запрещающих копирование (например, ссылок). Этот сгенерированный оператор выполняет почленное копирование (member-wise copy) для всех нестатических полей и базовых подобъектов.
Пример сгенерированного поведения:
class Example {
public:
int value;
std::string name;
int* dynamic_data;
};
Example obj1;
obj1.value = 42;
obj1.name = "Test";
obj1.dynamic_data = new int(100);
Example obj2;
obj2 = obj1; // Вызов сгенерированного operator=
// obj2.value = obj1.value (копирование int)
// obj2.name = obj1.name (копирование std::string работает корректно)
// obj2.dynamic_data = obj1.dynamic_data (ПРОБЛЕМА: копируется указатель, а не данные!)
Ключевые проблемы сгенерированного оператора:
- Поверхностное копирование указателей (Shallow Copy): Оба объекта начинают владеть одним и тем же ресурсом в динамической памяти.
- Утечки памяти: Старые данные
obj2.dynamic_dataне освобождаются. - Двойное освобождение: Деструкторы обоих объектов попытаются освободить одну и ту же память, что ведет к неопределенному поведению.
Решение — реализация оператора присваивания копированием (часть "Правила трех/пяти"):
class Example {
int* dynamic_data;
size_t size;
public:
// Пользовательский оператор присваивания копированием
Example& operator=(const Example& other) {
if (this != &other) { // Защита от самоприсваивания (a = a)
// 1. Освобождаем старые ресурсы
delete[] dynamic_data;
// 2. Выделяем новую память и копируем данные
size = other.size;
dynamic_data = new int[size];
std::copy(other.dynamic_data, other.dynamic_data + size, dynamic_data);
}
return *this; // Возвращаем ссылку на текущий объект
}
// ... также нужны конструктор копирования и деструктор
};
Идиома "Copy-and-Swap" — более надежная и безопасная альтернатива, которая также обеспечивает строгую гарантию исключений.
Example& operator=(Example other) { // Параметр передается по значению (копируется)
swap(*this, other); // Обмениваем содержимое текущего объекта и копии
return *this;
// Деструктор параметра `other` освободит старые ресурсы
}