Безопасно ли "удалить это"?
В моих начальных базовых тестах это совершенно безопасно. Однако меня поразило, что попытка манипулировать this
позже в функции, которая delete
s 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
}