Сделайте присваивание копии безопасным для самоприсваивания
Причина
Если x = x изменит значение x, людей это удивит и произойдут плохие ошибки (часто включая утечки памяти).
Пример
Контейнеры стандартной библиотеки элегантно и эффективно обрабатывают самоприсваивание:
std::vector<int> v = {3, 1, 4, 1, 5, 9};
v = v;
// значение v остается {3, 1, 4, 1, 5, 9}
Примечание
Присваивание по умолчанию, генерируемое из членов, которые правильно обрабатывают самоприсваивание, корректно обрабатывает самоприсваивание.
struct Bar {
vector<pair<int, int>> v;
map<string, int> m;
string s;
};
Bar b;
// ...
b = b; // корректно и эффективно
Примечание
Вы можете обработать самоприсваивание путем явной проверки на самоприсваивание, но часто быстрее и элегантнее справиться без такой проверки (например, используя swap).
class Foo {
string s;
int i;
public:
Foo& operator=(const Foo& a);
// ...
};
Foo& Foo::operator=(const Foo& a) // OK, но есть затраты
{
if (this == &a) return *this;
s = a.s;
i = a.i;
return *this;
}
Это очевидно безопасно и, похоже, эффективно. Однако что, если мы сделаем одно самоприсваивание на миллион присваиваний? Это примерно миллион избыточных проверок (но поскольку ответ по сути всегда одинаков, предсказатель ветвлений компьютера практически всегда угадает правильно). Рассмотрите:
Foo& Foo::operator=(const Foo& a) // проще и, вероятно, намного лучше
{
s = a.s;
i = a.i;
return *this;
}
std::string безопасна для самоприсваивания, как и int. Все затраты приходятся на (редкий) случай самоприсваивания.
Применение
(Простое) Операторы присваивания не должны содержать паттерн if (this == &a) return *this; ???