оператор = в my_unique_ptr не является exception-safe
alexey-malov opened this issue · comments
course-nimble_cpp/container_4.hpp
Lines 29 to 33 in 8059da2
если new выбросит исключение, то data_ будет указывать на удалённый адрес, и повторный delete в деструкторе приведёт к undefined behavior.
Кроме того, нет защиты от самоприсваивания - также будет UB при разыменовании удалённого указателя.
Лучше исправить на что-то такое:
my_unique_ptr& operator=(const my_unique_ptr& p) {
if (&p != this)
{
auto data = (p.data_ ? new int{*p.data_} : nullptr);
delete data_;
data_ = data;
}
return *this;
}
Либо вместо этих двух
my_unique_ptr& operator=(const my_unique_ptr& p) {
delete data_;
data_ = (p.data_ ? new int{*p.data_} : nullptr);
return *this;
}
my_unique_ptr& operator=(my_unique_ptr&& p) {
std::swap(data_, p.data_);
return *this;
}
сделать один
my_unique_ptr& operator=(my_unique_ptr p) {
std::swap(data_, p.data_);
return *this;
}
Такой "универсальный" оператор присваивания нельзя будет сделать noexcept в "оптимизированной" версии. А тут за счёт noexcept был в бенчмарке прирост раза в 1,5-2.
Можно "универсальный" оператор сделать noexcept, т.к. noexcept будет относиться только к содержимому функции между фигурными скобками и конструктор временного объекта под noexcept не попадёт. Но это немного непривычная конструкция...