Почему я не должен пытаться использовать «это» значение после «удаления этого»?

StackOverflow https://stackoverflow.com/questions/1866461

  •  18-09-2019
  •  | 
  •  

Вопрос

В Этот параграф из C ++ FAQ Использование delete this конструкция обсуждается. 4 ограничения перечислены.

Ограничения от 1 до 3 выглядят вполне разумно. Но почему ограничение 4 там, что я «не должен изучать его, сравнивать его с другим указателем, сравнить его с нулевым, распечатать, отбрасывать, делать что -нибудь с ним»?

Я имею в виду this это еще один указатель. Почему я не могу reinterpret_cast это до int или позвоните по телефону printf() вывести его значение?

Это было полезно?

Решение

Причина, по которой вы не можете ничего сделать с указателем после того, как вы удалите его (это или любой другой указатель), заключается в том, что аппаратное обеспечение может (и некоторые старые машины) ловили, пытаясь загрузить недопустимый адрес памяти в регистр. Несмотря на то, что это может быть хорошо для всех современных аппаратных средств, стандарт говорит, что единственное, что вы можете сделать с недействительным указателем (неонициализированным или удаленным), - это назначить ему (нулевое или из другого допустимого указателя).

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

Значение «этого» после вызова удаления не определена, и поведение всего, что вы с ним делаете, также не определено. Хотя я ожидаю, что большинство компиляторов сделают что-то разумное, нет ничего (в спецификации), не помешая компилятору решить, что его поведение в этом конкретном случае будет испускать код для форматирования вашего жесткого диска. Вызов неопределенного поведения (почти) всегда ошибка, даже когда ваш конкретный компилятор ведет себя так, как вам это хотелось.

Вы можете обойти это, взяв копию указателя (как целое число), прежде чем позвонить удалить.

Ага!

3.7.3.2/4: «... Функция Deallocation должна рассматривать хранилище, на которое ссылается указатель, что делает недействительными, все указатели, относящиеся к любой части хранилища с динамикой. Эффект использования недопустимого значения указателя (включая его передачу в Deallocation функция) не определен ».

Обратите внимание, что это написано «Использование значения», а не «вытеснение указателя».

Этот абзац не зависит от this, это относится ко всему, что было удалено.

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

Теперь некоторые из действий, на которые вы указываете, могут быть, по -видимому, «безопасными», но трудно сказать, что происходит в любом методе, который вы можете позвонить.

Из сообщения: «Не должен изучить его, сравнить его с другим указателем, сравните его с NULL, распечатайте, отбрасывайте, делайте что -нибудь с ним»?

Все эти действия могут вызвать функции, связанные с оператором, которые оцениваются с помощью неопределенного указателя. То же самое для кастинга.

Теперь, если вы выполняете reintepret_cast, это, вероятно, другая история, и вы, вероятно, могли бы ладить с ним, так как переосмысление - это немного путем переосмысления, без участия (насколько я знаю) любой метод вызова.

По той же причине вы не удалите ни одного другого указателя, а затем попытаетесь выполнить какие -либо операции на нем.

б/в адрес, к которому это относится сейчас, он не определен, и вы не знаете, что может быть там ...

В многопоточной программе, в тот момент, когда вы delete Указатель, свободное пространство может быть выделено другой нитью, перезаписывая пространство, используемое this. Анкет Даже в программе с одной точки returnвсе, что вы делаете после delete this может выделить память и перезаписать то, на что раньше указывалось this.

В исполнении Microsoft Visual C ++, скомпилированном в режиме отладки, deleteУказатель приводит к тому, что его память сразу перезаписывается тестовым рисунком 0xCC (ненициализированные переменные также инициализируются с помощью этой шаблона), чтобы помочь в определении висящих ошибок указателя, таких как этот.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top