Когда я пишу демонстрационный строковый класс, в функции назначения копирования я пытаюсь очистить себя с помощью «удалить это» перед копированием. Но это не удалось.
Str &operator=(const Str &s) {
if (this != &s) { // self-assignment check
//delete this; //cannot run as I imagine
this->~Str();
_size = s._size;
_str = new char[_size + 1];
memcpy(_str, s._str, _size + 1);
}
return *this;
}
~Str() {
_size = 0;
delete[] _str;
}
Линукс сказал мне
двойной свободный или коррупция (аут) Прервано (сброшено ядро)
delete this
запускает деструктор и освобождает всю память, предоставленную вашему объекту. Просто напишите отдельную функцию «dealloc» и вызовите ее вместо того, чтобы играть с деструктором.
@ALX23z Не free(this);
, а operator delete(this);
.
Пожалуйста, прочтите также: Что такое правило трех?
delete x;
эквивалентно x->~T();
, за которым следует operator delete(x)
(что похоже на free(x)
, но может быть несовместимо с ним).
x->~T();
— опасный инструмент. В этом случае за ним должен следовать new(this) T(...);
(размещение-новое) для вызова конструктора, иначе текущий объект считается «мертвым», и любое взаимодействие с ним вызывает неопределенное поведение.
Но даже если вы вызовете Placement-new, он может бросить вызов. Тогда объект остается мёртвым, а вызывающая сторона получает UB, когда снова пытается уничтожить уже мёртвый объект.
Вывод: x->~T();
сложно использовать правильно, используйте что-то другое.
Либо напишите функцию, которая делает то же самое, что и деструктор, и вместо этого вызовите ее. В отличие от деструктора, объект не будет считаться мертвым после его вызова, поэтому новое размещение не требуется.
Или используйте идиому копирования и замены. Напишите задание так:
Str &operator=(Str s) noexcept
{
std::swap(_str, s._str);
std::swap(_size, s._size);
return *this;
}
Это универсальный способ написания заданий. Он работает как при копировании, так и при перемещении, безопасен для исключений и т. д.
Я думаю, что наиболее разумное использование x->~T();
- это если вы создали объект с новым размещением.
@user253751 user253751 Ммм, я имел в виду только то, что это не подходит для этого варианта использования.
Другая ловушка с x->~T()
, за которой следует размещение new, заключается в том, что если исходный тип объекта, на который указывает x
, был типом U
, производным от T
, результатом будет нежизнеспособный гибрид, который не является ни T
, ни U
.
Ваш delete this
уже выполняется this->~Str()
, но это только одна проблема. После delete this
вы называете _size = s._size
, что на самом деле this->_size = s._size
. Но время жизни this
уже закончилось, поэтому любой вызов this
может привести к неопределенному поведению. Так что ни delete this
, ни this->~Str()
не принадлежат вашему оператору назначения.
@Retired Ninja хорошая мысль.
delete this
звонкиthis->~Obj();
иfree(this)
. Объекты удаляются черезdelete
, когда они были созданы черезnew
. В то время какthis->~Obj();
вручную вызывает деструктор, который будет использоваться с новым размещением.