Это «бомба замедленного действия», только если вы педантичны по поводу формулировки спецификации.Однако, несмотря на это, это ужасный, опрометчивый подход, потому что он скрывает программную ошибку.Только по этой причине я бы удалил , даже если это потребует значительных усилий.Это не непосредственный (или даже среднесрочный) риск, но он не очень хороший подход.
Такое поведение, скрывающее ошибки, на самом деле тоже не то, на что вы хотите положиться.Представьте, что вы полагаетесь на это поведение (т. Е. , не имеет значения, допустимы ли мои объекты, оно все равно будет работать! ), а затем, при некоторой опасности, компилятор оптимизирует оператор if
в конкретномслучай, потому что это может доказать, что this
не является нулевым указателем.Это законная оптимизация не только для некоторого гипотетического будущего компилятора, но и для очень реальных современных компиляторов.
Но, конечно, поскольку ваша программа не правильно сформирована, она происходит что в какой-то момент вы передаете ему ноль this
вокруг 20 углов.Черт, ты мертв.
Это очень надумано, правда, и этого не произойдет, но ты не можешь быть на 100% уверен, что это все еще не может произойти.
Примечаниечто, когда я выкрикиваю «удалить!», это не означает, что все они должны быть удалены немедленно или в ходе одной крупной операции по подбору рабочей силы.Вы можете удалить эти проверки одну за другой, когда сталкиваетесь с ними (когда вы все равно что-то изменяете в одном и том же файле, избегаете перекомпиляций), или просто выполнять поиск по тексту (желательно в часто используемой функции) и удалить эту.
Поскольку вы используете GCC, вы можете указать в __builtin_return_address
, что может помочь вам удалить эти проверки без огромных трудовых ресурсов и полностью нарушить весь рабочий процесс и сделать приложение полностью непригодным для использования.
Перед тем, как снимите флажок, измените его на, чтобы вывести адрес вызывающего абонента, и addr2line
сообщит вам местоположение в вашем источнике.Таким образом, вы сможете быстро определить все местоположения в приложении, которые ведут себя неправильно, поэтому вы можете исправить их.
Таким образом, вместо
if(!this) return 0;
измените одно местоположение ввремя что-то вроде:
if(!this) { __builtin_printf("!!! %p\n", __builtin_return_address(0)); return 0; }
Это позволяет вам идентифицировать недопустимые сайты вызовов для этого изменения, в то же время позволяя программе «работать как задумано» (вы также можете запросить вызывающего абонента при необходимости).Исправьте каждое плохое место, один за другим.Программа по-прежнему будет «работать» в обычном режиме.
Если адреса больше не появляются, удалите проверку полностью.Возможно, вам все равно придется исправить один или другой сбой, если вам не повезло (потому что он не показывал, пока вы тестировали), но это должно случаться очень редко.В любом случае это должно помешать вашему коллеге кричать на вас.
Снимите один или два чека в неделю, и в конечном итоге ни один не останется.Между тем, жизнь продолжается, и никто не замечает, что вы делаете вообще.
TL; DR
Что касается "текущих версий GCC", вы подойдете для не виртуальныхфункции, но, конечно, никто не может сказать, что может сделать будущая версия.Однако я считаю крайне маловероятным, что в будущей версии ваш код будет поврежден.Не у некоторых существующих проектов есть такая проверка (я помню, что у нас было буквально сотни из них при завершении кода Code :: Blocks когда-то, не спрашивайте меня почему!).Производители компиляторов, вероятно, не хотят, чтобы десятки / сотни главных разработчиков проектов были недовольны намеренно, только чтобы доказать свою точку зрения.
Также рассмотрим последний абзац («с логической точки зрения»).Даже если эта проверка завершится с ошибкой и сгорит с будущим компилятором, она все равно будет аварийно завершена.
Оператор if(!this) return;
несколько бесполезен, поскольку this
не может быть нулевым указателем в правильно сформированной программе (это означает, что вы вызвали функцию-член для нулевого указателя).Это не значит, конечно, что это не могло произойти.Но в этом случае программа должна аварийно завершить работу или прервать работу с утверждением.Ни при каких условиях такая программа не должна продолжать молча.
С другой стороны, вполне возможно вызвать функцию-член для недопустимого объекта, который оказывается не нулевым .Проверка, является ли this
нулевой указатель, очевидно, не уловит этот случай, но это точно такой же UB.Таким образом, помимо скрытия неправильного поведения, эта проверка также обнаруживает только половину проблемных случаев.
Если вы придерживаетесь формулировки уточнения, используя this
(который включает проверку, является ли это нулевым указателем)) неопределенное поведение.Строго говоря, это «бомба замедленного действия».Тем не менее, я бы разумно не счел бы это проблемой, как с практической, так и с логической точки зрения.
- С практической точки зрениявидимо, на самом деле не имеет значения, читаете ли вы указатель, который недопустим, если вы не разыменовываете его.Да, строго по письму это запрещено.Да, теоретически кто-то может создать процессор, который будет проверять недействительные указатели, когда вы загружаете их, и выдает ошибку.Увы, это не тот случай, если вы реальны.
- С логической точки зрения, предполагая, что проверка взорвет , онавсе еще не произойдет.Для выполнения этого оператора функция-член должна быть вызвана и (виртуальная или нет, встроенная или нет) использует недействительный
this
, который он делает доступным внутри тела функции.Если одно незаконное использование this
взорвется, другое тоже.Таким образом, проверка устаревает, потому что программа уже аварийно завершает работу.
nb: Эта проверка очень похожа на "идиому безопасного удаления", которая устанавливает указатель на nullptr
после его удаления (с помощью макроса или шаблонной функции safe_delete
).Предположительно, это «безопасно», потому что не приводит к сбою, удаляя один и тот же указатель дважды.Некоторые люди даже добавляют избыточный if(!ptr) delete ptr;
.
Как вы знаете, operator delete
гарантированно не будет работать с нулевым указателем.Что означает не больше и не меньше, чем, установив указатель на нулевой указатель, вы успешно устранили единственный шанс обнаружить двойное удаление (это программная ошибка, которую нужно исправить!).Он не является более «безопасным», но вместо этого скрывает некорректное поведение программы.Если вы дважды удаляете объект, программа должна аварийно завершить работу.
Вы должны либо оставить удаленный указатель в одиночку, либо, если вы настаиваете на манипулировании, установить ненулевой недействительный указатель (такойв качестве адреса специальной «недопустимой» глобальной переменной или магического значения, например -1
, если хотите - но вы не должны пытаться обманывать и скрывать сбой, когда это произойдет).