Безопасно ли "удалить это"?

В моих начальных базовых тестах это совершенно безопасно. Однако меня поразило, что попытка манипулировать this позже в функции, которая deletes this может быть ошибка во время выполнения. Это правда, и обычно ли это безопасно delete this? или есть только определенные случаи, когда это безопасно?

10 ответов

Решение

delete this является законным и делает то, что вы ожидаете: он вызывает деструктор вашего класса и освобождает основную память. После delete this возвращается, ваш this значение указателя не изменяется, поэтому теперь это повисший указатель, который не должен быть разыменован. Это включает в себя неявную разыменование с использованием переменных-членов класса.

В классах с подсчетом ссылок обычно обнаруживается, что, когда ref-count уменьшается до 0, DecrementRefCount() / Release() / любой вызов функции-члена delete this,

delete this как правило, считается очень плохой формой по многим причинам. Легко получить доступ к переменным-членам после delete this, Код вызывающей стороны может не понимать, что ваш объект самоуничтожен.

Также, delete this это "запах кода", что ваш код может не иметь симметричной стратегии владения объектом (кто выделяет, а кто удаляет). Объект не мог бы выделить себя new так зовет delete this означает, что класс A выделяет объект, но класс B позже освобождает его [self].

Удалить "this" безопасно, если это последняя операция в методе. Фактически, некоторые API профессионального уровня делают это (см. Пример реализации ATL CComObject).

Единственная опасность - попытаться получить доступ к любым другим данным члена после вызова "удалить это". Это, конечно, небезопасно.

Удалить это совершенно законно, как уже упоминали другие. Это рискованно по одной дополнительной причине, которая еще не была упомянута - вы предполагаете, что объект был размещен в куче. Это может быть сложно гарантировать, хотя в случае реализации подсчета ссылок это, как правило, не проблема.

Но не делай этого в деструкторе!

Как утверждают другие, delete это допустимая идиома, но для ее безопасности необходимо убедиться, что объект никогда не создается в стеке.

Один из способов сделать это - сделать как конструктор, так и деструктор частным и принудительно создать объект с помощью функции фабрики классов, которая создает объект в куче и возвращает указатель на него. Фабрика классов может быть статической функцией-членом или функцией-другом. Затем можно выполнить очистку с помощью метода Delete() для объекта, который "удаляет это". COM-объекты в основном работают таким образом, за исключением того, что, кроме того, они подсчитываются с помощью ссылки "delete this", возникающей, когда счетчик ссылок уменьшается до нуля.

Удалить это может вызвать проблему, когда у вас есть подклассы объекта, который вы удаляете. Помните, что строительство начинается сверху вниз, а удаление начинается снизу вверх. Таким образом, если удалить это в середине иерархии, вы в основном потеряли все объекты ниже этого конкретного класса.

Удалить это очень удобно, когда вы реализуете объект с подсчетом ссылок, примером которого являются классы COM.

Да. Это должно быть прекрасно. "Это" просто указатель. Любой указатель будет делать для удаления. Информация о том, как удалить объект, содержится в записях кучи. Вот как IUnknown::Release() обычно реализуется в COM-объектах.

Юридический Да
Сейф Нет

Читайте для аналогичного обсуждения. Ваше понимание верно в том смысле, что оно работает, необходимо и может быть опасно, поскольку впоследствии вы не сможете получить к нему доступ.

Если вы наследуете от базового класса и дали удалить его в функции базового класса, использование указателя на производный класс вызовет сбой. Например:

class Base
{

    virtual void Release()
    {
        delete this;
    }

}

class Derived : public Base
{

    void Foo()
    {
        ...
    }

}

main()
{

    Base *ptrDerived = new Derived();
    ptrDerived->release();
    ptrDerived->Foo() //Crash

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