Разрешено ли, delete this;
если оператор delete является последним оператором, который будет выполнен в этом экземпляре класса? Конечно, я уверен, что объект, представленный this
-pointer, new
создан.
Я думаю о чем-то вроде этого:
void SomeModule::doStuff()
{
// in the controller, "this" object of SomeModule is the "current module"
// now, if I want to switch over to a new Module, eg:
controller->setWorkingModule(new OtherModule());
// since the new "OtherModule" object will take the lead,
// I want to get rid of this "SomeModule" object:
delete this;
}
Я могу это сделать?
c++
memory-management
new-operator
delete-operator
self-destruction
Мартейн Курто
источник
источник
delete this
создали тесную связь между классом и методом выделения, используемым для создания объектов этого класса. Это очень плохой дизайн ОО, так как самое основное в ООП - создавать автономные классы, которые не знают или не заботятся о том, что делает их вызывающая программа. Таким образом, правильно разработанный класс не должен знать или заботиться о том, как он был распределен. Если вам по какой-то причине нужен такой своеобразный механизм, я думаю, что лучше было бы использовать класс-оболочку вокруг фактического класса и позволить обертке иметь дело с распределением.setWorkingModule
?Ответы:
C ++ FAQ Lite имеет запись специально для этого
Я думаю, что эта цитата хорошо подводит итог
источник
Да,
delete this;
он определил результаты, если (как вы заметили) вы гарантируете, что объект был распределен динамически, и (конечно) никогда не пытаетесь использовать объект после его уничтожения. За прошедшие годы было задано много вопросов о том, о чем конкретно говорится в стандартеdelete this;
, в отличие от удаления какого-либо другого указателя. Ответ на это довольно короткий и простой: он ничего не говорит о многом. Он просто говорит, чтоdelete
операндом должно быть выражение, обозначающее указатель на объект или массив объектов. В нем подробно рассказывается о том, как выяснить, какую (если есть) функцию освобождения вызывать для освобождения памяти, но весь разделdelete
(§ [expr.delete])delete this;
конкретно не упоминается . Раздел о деструкторах не упоминаетdelete this
в одном месте (§ [class.dtor] / 13):Это имеет тенденцию поддерживать идею, которую стандарт считает
delete this;
действительным - если он был недействительным, его тип не был бы значимым.delete this;
Насколько я знаю , это единственное место, которое упоминает стандарт .Во всяком случае, некоторые считают
delete this
мерзкий взлом и говорят всем, кто будет слушать, что его следует избегать. Одной из часто упоминаемых проблем является сложность обеспечения того, чтобы объекты класса только когда-либо выделялись динамически. Другие считают это вполне разумной идиомой и используют ее постоянно. Лично я где-то посередине: я редко использую его, но не стесняйтесь делать это, когда он кажется подходящим инструментом для работы.Основное время, когда вы используете эту технику, - это объект, жизнь которого почти полностью принадлежит ему. Одним из примеров, приведенных Джеймсом Канзе, была система биллинга / отслеживания, над которой он работал в телефонной компании. Когда вы начинаете делать телефонный звонок, что-то принимает это к сведению и создает
phone_call
объект. С этого моментаphone_call
объект обрабатывает детали телефонного звонка (установление соединения при наборе номера, добавление записи в базу данных, чтобы сообщить, когда начался звонок, возможно, подключить больше людей, если вы делаете конференц-связь, и т. Д.) Когда последние люди, находящиеся на вызове, вешают трубку,phone_call
объект ведет окончательный учет (например, добавляет запись в базу данных, чтобы сказать, когда вы положили трубку, чтобы они могли вычислить, как долго длился ваш вызов), а затем уничтожает себя. Время жизниphone_call
Объект основан на том, когда первый человек начинает вызов и когда последние покидают вызов - с точки зрения остальной части системы, это в основном совершенно произвольно, поэтому вы не можете привязать его к какой-либо лексической области в коде или что-нибудь в этом порядке.Для всех, кому небезразлично, насколько надежным может быть этот вид кодирования: если вы делаете телефонный звонок в, из или через почти любую часть Европы, есть очень хороший шанс, что он обрабатывается (по крайней мере частично) кодом это делает именно это.
источник
bool selfDelete
в конструктор параметр, который присваивается переменной-члену. Конечно, это означает передачу программисту достаточного количества веревки, чтобы завязать в ней петлю, но я считаю, что это предпочтительнее утечек памяти.this
. Да, код обрабатывается точноthis
. ;)Если вас это пугает, есть совершенно законный взлом:
Я думаю, что
delete this
это идиоматический C ++, и я представляю это только как любопытство.Есть случай, когда эта конструкция действительно полезна - вы можете удалить объект после создания исключения, для которого нужны данные члена из объекта. Объект остается действительным до тех пор, пока не произойдет бросок.
Примечание: если вы используете компилятор старше C ++ 11, который вы можете использовать
std::auto_ptr
вместо негоstd::unique_ptr
, он сделает то же самое.источник
unique_ptr
из другогоunique_ptr
требует перемещения, но не из необработанного указателя. Разве вещи не изменились в C ++ 17?Одной из причин, по которой был разработан C ++, было упрощение повторного использования кода. В общем, C ++ должен быть написан так, чтобы он работал независимо от того, создается ли класс в куче, в массиве или в стеке. «Удалить это» - очень плохая практика кодирования, потому что она будет работать, только если в куче определен один экземпляр; и не должно быть другого оператора delete, который обычно используется большинством разработчиков для очистки кучи. Это также предполагает, что ни один программист по техническому обслуживанию в будущем не излечит ложно воспринятую утечку памяти, добавив оператор удаления.
Даже если вы заранее знаете, что ваш текущий план состоит в том, чтобы выделить только один экземпляр в куче, что если в будущем появится какой-нибудь счастливчик-разработчик и решит создать экземпляр в стеке? Или, что если он вырезает и вставляет определенные части класса в новый класс, который он намеревается использовать в стеке? Когда код достигает «удалить это», он отключается и удаляет его, но затем, когда объект выходит из области видимости, он вызывает деструктор. Затем деструктор попытается удалить его снова, а затем вы попадаете. В прошлом подобные действия приводили к сбоям не только с программой, но и с операционной системой и компьютером. В любом случае, это крайне НЕ рекомендуется, и его почти всегда следует избегать. Я был бы в отчаянии, серьезно оштукатурен,
источник
Это разрешено (просто не используйте объект после этого), но я бы не стал писать такой код на практике. Я думаю , что
delete this
должно появиться только в функциях , которые называютсяrelease
илиRelease
и выглядит следующим образом :void release() { ref--; if (ref<1) delete this; }
.источник
Что ж, в конструкции Component Object Model (COM)
delete this
может быть частьюRelease
метода, который вызывается всякий раз, когда вы хотите освободить искомый объект:источник
Это основная идиома для объектов с подсчетом ссылок.
Подсчет ссылок является сильной формой детерминированной сборки мусора - он гарантирует, что объекты управляют своим собственным временем жизни вместо того, чтобы полагаться на «умные» указатели и т. Д., Чтобы сделать это для них. Доступ к базовому объекту возможен только через интеллектуальные указатели «Reference», разработанные таким образом, чтобы указатели увеличивали и уменьшали целое число членов (счетчик ссылок) в реальном объекте.
Когда последняя ссылка удаляется из стека или удаляется, счетчик ссылок становится равным нулю. Поведением вашего объекта по умолчанию будет вызов «удалить это» для сборки мусора - библиотеки, которые я пишу, предоставляют защищенный виртуальный вызов «CountIsZero» в базовом классе, чтобы вы могли переопределить это поведение для таких вещей, как кэширование.
Ключом к тому, чтобы сделать это безопасным, является не предоставление пользователям доступа к КОНСТРУКТОРУ рассматриваемого объекта (сделать его защищенным), но вместо этого заставление их вызывать некоторый статический член - ФАБРИКА - как «Статическая ссылка CreateT (...)». Таким образом, вы ЗНАЕТЕ, что они всегда построены с обычным «новым» и что необработанный указатель недоступен, поэтому «удалить это» никогда не взорвется
источник
Вы можете сделать это. Тем не менее, вы не можете назначить это. Таким образом, причина, по которой вы заявляете для этого «я хочу изменить взгляд», кажется очень сомнительной. На мой взгляд, лучшим методом будет объект, который содержит представление, чтобы заменить это представление.
Конечно, вы используете объекты RAII и вам вообще не нужно вызывать delete ... верно?
источник
Это старый вопрос с ответом, но @Alexandre спросил: «Зачем кому-то это делать?», И я подумал, что могу привести пример использования, которое я рассматриваю сегодня днем.
Устаревший код. Использует голые указатели Obj * obj с удалением obj в конце.
К сожалению, иногда мне нужно, а не часто, поддерживать объект дольше.
Я рассматриваю вопрос об умном указателе. Но было бы много кода, чтобы изменить, если бы я должен был использовать
ref_cnt_ptr<Obj>
везде. И если вы смешаете голый Obj * и ref_cnt_ptr, вы можете неявно удалить объект, когда последний ref_cnt_ptr исчезнет, даже если Obj * еще жив.Поэтому я подумываю о создании явного_отделения_ref_cnt_ptr. Т.е. указатель с подсчетом ссылок, где удаление выполняется только в явной процедуре удаления. Я использую его в одном месте, где существующий код знает время жизни объекта, а также в моем новом коде, который поддерживает объект дольше.
Увеличение и уменьшение счетчика ссылок, как манипулируют явным
Но НЕ освобождается, когда счетчик ссылок считается равным нулю в деструкторе явной_далеты_ref_cnt_ptr.
Только освобождение, когда счетчик ссылок считается нулевым в явной операции удаления. Например, что-то вроде:
ОК, что-то в этом роде. Немного необычно иметь указатель со счетчиком ссылок, который не удаляет автоматически объект, на который указывает указатель rc'ed ptr. Но кажется, что это может сделать смешивание обнаженных указателей и rc'ed указателей более безопасным.
Но пока нет необходимости удалять это.
Но потом мне пришло в голову: если объект, на который указывает указатель, знает, что на него подсчитывается ссылка, например, если счетчик находится внутри объекта (или в какой-то другой таблице), тогда процедура delete_if_rc0 может быть методом объект-указатель, а не (умный) указатель.
На самом деле, он вовсе не должен быть методом-членом, но может быть бесплатной функцией:
(Кстати, я знаю, что код не совсем правильный - он становится менее читаемым, если я добавляю все детали, поэтому я оставляю это так.)
источник
Удалить это разрешено, пока объект находится в куче. Вы должны будете требовать, чтобы объект был только кучей. Единственный способ сделать это - сделать деструктор защищенным - таким образом удаление может быть вызвано ТОЛЬКО из класса, поэтому вам потребуется метод, обеспечивающий удаление.
источник