Ответ
Оператор присваивания копированием (operator=) вызывается, когда существующему объекту присваивается значение другого существующего объекта того же типа. Это не конструктор, а оператор, который модифицирует состояние уже созданного объекта.
Типичные сценарии вызова:
MyClass a, b, c;
a = b; // (1) Прямое присваивание одного объекта другому
c = a = b; // (2) Цепочка присваиваний (возвращает ссылку на левый операнд)
std::vector<MyClass> vec(5);
vec[0] = vec[1]; // (3) Присваивание элементам контейнеров
Ключевые требования к реализации:
- Проверка на самоприсваивание:
if (this == &other) return *this; - Освобождение старых ресурсов: Перед копированием новых данных нужно корректно освободить ресурсы, которыми владел текущий объект.
- Копирование данных: Скопировать (или клонировать) данные из
otherв текущий объект. - Возврат ссылки на текущий объект: Для поддержки цепочек присваивания.
Пример реализации для класса, управляющего сырой памятью:
class Buffer {
char* data;
size_t size;
public:
// Конструктор по умолчанию
Buffer(size_t sz = 0) : size(sz), data(size ? new char[size] : nullptr) {}
// Деструктор
~Buffer() { delete[] data; }
// Конструктор копирования (для Rule of Three/Five)
Buffer(const Buffer& other) : size(other.size), data(size ? new char[size] : nullptr) {
std::copy(other.data, other.data + size, data);
}
// Оператор присваивания копированием (Copy Assignment Operator)
Buffer& operator=(const Buffer& other) {
if (this != &other) { // (1) КРИТИЧНО: проверка на самоприсваивание
// (2) Освобождаем старые ресурсы
delete[] data;
// (3) Копируем новые данные
size = other.size;
data = size ? new char[size] : nullptr;
std::copy(other.data, other.data + size, data);
}
// (4) Возвращаем *this
return *this;
}
};
Современный подход (Copy-and-Swap idiom): Часто оператор присваивания реализуют через передачу параметра по значению и обмен (swap), что автоматически обеспечивает строгую гарантию исключений и защиту от самоприсваивания.
Buffer& operator=(Buffer other) { // Параметр передаётся по значению (копируется)
swap(*this, other); // Обмениваем содержимое текущего объекта и временной копии
return *this; // Временная копия (со старыми данными) уничтожается при выходе
}