Разница между `delete this` и `this->~Obj` в C++

Когда я пишу демонстрационный строковый класс, в функции назначения копирования я пытаюсь очистить себя с помощью «удалить это» перед копированием. Но это не удалось.

    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 звонки this->~Obj(); и free(this). Объекты удаляются через delete, когда они были созданы через new. В то время как this->~Obj(); вручную вызывает деструктор, который будет использоваться с новым размещением.
ALX23z 13.02.2023 13:52
delete this запускает деструктор и освобождает всю память, предоставленную вашему объекту. Просто напишите отдельную функцию «dealloc» и вызовите ее вместо того, чтобы играть с деструктором.
Botje 13.02.2023 13:53
Разрешено ли «удалить это» в C++? Стоит прочитать.
Retired Ninja 13.02.2023 13:53

@ALX23z Не free(this);, а operator delete(this);.

HolyBlackCat 13.02.2023 13:54

Пожалуйста, прочтите также: Что такое правило трех?

Karl Knechtel 13.02.2023 13:56
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы
HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!
Современный фронтенд похож на старую добрую веб-разработку, но с одной загвоздкой: страница в браузере так же сложна, как и бэкенд.
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
Узнайте, как использовать теги <ul> и <li> для создания неупорядоченных списков в HTML
HTML предоставляет множество тегов для структурирования и организации содержимого веб-страницы. Одним из наиболее часто используемых тегов для...
1
5
107
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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 13.02.2023 14:20

@user253751 user253751 Ммм, я имел в виду только то, что это не подходит для этого варианта использования.

HolyBlackCat 13.02.2023 15:18

Другая ловушка с x->~T(), за которой следует размещение new, заключается в том, что если исходный тип объекта, на который указывает x, был типом U, производным от T, результатом будет нежизнеспособный гибрид, который не является ни T, ни U.

Pete Becker 13.02.2023 17:10

Ваш delete this уже выполняется this->~Str(), но это только одна проблема. После delete this вы называете _size = s._size, что на самом деле this->_size = s._size. Но время жизни this уже закончилось, поэтому любой вызов this может привести к неопределенному поведению. Так что ни delete this, ни this->~Str() не принадлежат вашему оператору назначения.

@Retired Ninja хорошая мысль.

fg grh 13.02.2023 15:14

Другие вопросы по теме