Является ли хорошей практикой обнулять указатель после его удаления?

150

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

Какие проблемы со следующим кодом?

Foo * p = new Foo;
// (use p)
delete p;
p = NULL;

Это было вызвано ответом и комментариями к другому вопросу. Один комментарий от Нила Баттерворта вызвал несколько голосов:

Установка указателей на NULL после удаления не является универсальной хорошей практикой в ​​C ++. Есть моменты, когда это полезно, и времена, когда это бессмысленно и может скрывать ошибки.

Есть много обстоятельств, когда это не поможет. Но по моему опыту, это не повредит. Кто-нибудь просветите меня.

Марк Рэнсом
источник
6
@ Андре: Технически это не определено. Вероятно, что вы получите доступ к той же памяти, что и раньше, но теперь она может использоваться чем-то другим. Если вы удалите память дважды, это может затруднить поиск вашей программы. deleteТем не менее, это безопасно для нулевого указателя, что является одной из причин, по которой обнуление указателя может быть хорошим.
Дэвид Торнли
5
@ Андре Пена, это не определено. Часто это даже не повторяется. Вы устанавливаете указатель на NULL, чтобы сделать ошибку более заметной при отладке, и, возможно, чтобы сделать ее более повторяемой.
Марк Рэнсом
3
@ Андре: Никто не знает. Это неопределенное поведение. Это может привести к сбою с нарушением прав доступа или к перезаписи памяти, используемой остальной частью приложения. Языковой стандарт не дает никаких гарантий того, что происходит, и поэтому вы не можете доверять своему приложению, как только оно произошло. Он мог запустить ядерные ракеты или отформатировать ваш жесткий диск. это может повредить память вашего приложения, или это может заставить демонов вылететь из вашего носа. Все ставки сделаны.
jalf
16
Летающие демоны - это особенность, а не ошибка.
Jball
3
Этот вопрос не является дубликатом, потому что другой вопрос о C, а этот о C ++. Многие ответы зависят от таких вещей, как умные указатели, которых нет в C ++.
Адриан Маккарти

Ответы:

86

Установка указателя на 0 (который является «нулевым» в стандартном C ++, определение NULL из C несколько отличается) позволяет избежать сбоев при двойном удалении.

Учтите следующее:

Foo* foo = 0; // Sets the pointer to 0 (C++ NULL)
delete foo; // Won't do anything

В то время как:

Foo* foo = new Foo();
delete foo; // Deletes the object
delete foo; // Undefined behavior 

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

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

Наконец, в качестве руководства по распределению объектов, я предлагаю вам взглянуть на std::unique_ptrстрогое / единичное владение, std::shared_ptrна общее владение или на другую реализацию интеллектуального указателя, в зависимости от ваших потребностей.

Håvard S
источник
13
Ваше приложение не всегда падает при двойном удалении. В зависимости от того, что происходит между двумя удалениями, может произойти все что угодно. Скорее всего, вы испортите свою кучу, и в какой-то момент вы потерпите крах в совершенно не связанном фрагменте кода. Хотя segfault обычно лучше, чем молчаливое игнорирование ошибки, в этом случае segfault не гарантируется, и это сомнительная утилита.
Адам Розенфилд
28
Проблема здесь в том, что у вас есть двойное удаление. Если указатель равен NULL, этот факт просто скрывается, он не исправляется и не становится безопаснее. Представьте себе, что через год он вернется и увидит, что foo удален. Теперь он считает, что может повторно использовать указатель, к сожалению, он может пропустить второе удаление (это может даже не быть в той же функции), и теперь повторное использование указателя теперь уничтожается при втором удалении. Любой доступ после второго удаления теперь является серьезной проблемой.
Мартин Йорк,
11
Это правда, установка указателя NULLможет маскировать ошибку двойного удаления. (Некоторые могут посчитать, что эта маска на самом деле является решением - да, но не очень хорошим, так как она не доходит до корня проблемы.) Но не установив ее в NULL, маски (FAR!) Больше общие проблемы доступа к данным после того, как они были удалены.
Адриан Маккарти
AFAIK, std :: auto_ptr устарел в будущем стандарте c ++
rafak
Я бы не сказал, что устарел, это звучит так, как будто идея просто ушла. Скорее, он заменяется unique_ptr, что делает то, что auto_ptrпытался сделать, семантикой перемещения.
GManNickG
55

Установка указателей на NULL после того, как вы удалили то, на что оно указывало, определенно не может повредить, но это часто немного помогает при более серьезной проблеме: почему вы вообще используете указатель? Я вижу две типичные причины:

  • Вы просто хотели что-то выделить в куче. В этом случае оборачивать его в объект RAII было бы намного безопаснее и чище. Завершите область видимости объекта RAII, когда он вам больше не нужен. Вот как это std::vectorработает, и это решает проблему случайного оставления указателей для освобождения памяти вокруг. Там нет указателей.
  • Или, возможно, вам нужна сложная семантика совместного владения. Указатель, возвращаемый из, newможет отличаться от того, который deleteвызывается. Несколько объектов, возможно, использовали объект одновременно. В этом случае общий указатель или что-то подобное было бы предпочтительным.

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

jalf
источник
15
Таким образом, вы выдвигаете аргумент, что в первую очередь не должно быть необработанного указателя, и что-либо, связанное с указанным указателем, не должно быть благословлено термином «хорошая практика»? Справедливо.
Марк Рэнсом
7
Ну, более или менее. Я бы не сказал, что ничто с использованием необработанного указателя не может быть названо хорошей практикой. Просто это скорее исключение, чем правило. Обычно наличие указателя является показателем того, что на более глубоком уровне что-то не так.
jalf
3
но, чтобы ответить на прямой вопрос, нет, я не вижу, как установка указателей на ноль может когда-либо вызывать ошибки.
jalf
7
Я не согласен - бывают случаи, когда указатель хорошо использовать. Например, в стеке есть 2 переменные, и вы хотите выбрать одну из них. Или вы хотите передать необязательную переменную в функцию. Я бы сказал, вы никогда не должны использовать необработанный указатель в сочетании с new.
rlbond
4
когда указатель вышел из области видимости, я не понимаю, как что-либо или кто-либо может с этим справиться.
Джалф
43

У меня есть еще лучшая практика: по возможности заканчивайте область видимости переменной!

{
    Foo* pFoo = new Foo;
    // use pFoo
    delete pFoo;
}
Дон Нойфельд
источник
17
Да, RAII твой друг. Оберните это в классе, и это станет еще проще. Или не обрабатывайте память самостоятельно, используя STL!
Брайан
24
Да, действительно, это лучший вариант. Не отвечает на вопрос, хотя.
Марк Рэнсом
3
Похоже, что это просто побочный продукт использования периода действия функций, и на самом деле это не решает проблему. Когда вы используете указатели, вы обычно передаете их копии в несколько уровней, и тогда ваш метод действительно бессмыслен в попытках решить проблему. Хотя я согласен, что хороший дизайн поможет вам изолировать ошибки, я не думаю, что ваш метод является основным средством для достижения этой цели.
Сан Хасинто
2
Если подумать, если бы вы могли это сделать, почему бы вам просто не забыть кучу и вытащить всю свою память из стека?
Сан Хасинто
4
Мой пример намеренно минимален. Например, вместо new, возможно, объект создается фабрикой, и в этом случае он не может помещаться в стек. Или, может быть, он не создан в начале области, но находится в некоторой структуре. Что я иллюстрирую, так это то, что этот подход обнаружит любое неправильное использование указателя во время компиляции , тогда как NULLing обнаружит любое неправильное использование во время выполнения .
Дон Нойфельд
31

Я всегда устанавливаю указатель на NULL(сейчас nullptr) после удаления объекта (ов), на который он указывает.

  1. Это может помочь отловить множество ссылок на освобожденную память (если предположить, что ваша платформа неисправна по нулевому указателю).

  2. Он не будет перехватывать все ссылки на свободную память, если, например, у вас есть копии указателя. Но некоторые лучше, чем ничего.

  3. Это будет маскировать двойное удаление, но я считаю, что они гораздо реже, чем доступ к уже освобожденной памяти.

  4. Во многих случаях компилятор собирается оптимизировать его. Таким образом, аргумент, что это ненужно, не убеждает меня.

  5. Если вы уже используете RAII, то не так много delete в вашем коде s, поэтому аргумент о том, что дополнительное назначение вызывает беспорядок, не убеждает меня.

  6. При отладке часто бывает удобно видеть нулевое значение, а не устаревший указатель.

  7. Если это все еще вас беспокоит, используйте вместо этого умный указатель или ссылку.

Я также установил для других типов дескрипторов ресурсов значение no-resource, когда ресурс free'd (который обычно находится только в деструкторе оболочки RAII, написанной для инкапсуляции ресурса).

Я работал над большим (9 миллионов заявлений) коммерческим продуктом (в основном на С). В какой-то момент мы использовали макро-магию для обнуления указателя при освобождении памяти. Это сразу выявило множество скрывающихся ошибок, которые были быстро исправлены. Насколько я помню, у нас никогда не было двойной ошибки.

Обновление: Microsoft считает, что это хорошая практика для обеспечения безопасности, и рекомендует эту практику в своих политиках SDL. Очевидно, что MSVC ++ 11 автоматически вытеснит удаленный указатель (во многих случаях), если вы скомпилируете с параметром / SDL.

Адриан Маккарти
источник
12

Во-первых, существует множество существующих вопросов по этой и тесно связанным темам, например, Почему не удаляется установка указателя на NULL? ,

В вашем коде проблема, что происходит (используйте p). Например, если где-то у вас есть такой код:

Foo * p2 = p;

затем установка p в NULL завершается очень мало, так как у вас все еще есть указатель p2, о котором нужно беспокоиться.

Нельзя сказать, что установка указателя на NULL всегда бессмысленна. Например, если p была переменной-членом, указывающей на ресурс, время жизни которого не было точно таким же, как у класса, содержащего p, то установка p в NULL могла бы быть полезным способом указания наличия или отсутствия ресурса.

Сообщество
источник
1
Я согласен, что бывают случаи, когда это не поможет, но вы, похоже, подразумеваете, что это может быть активно вредным. Это было ваше намерение, или я прочитал это неправильно?
Марк Рэнсом
1
Имеется ли копия указателя, не имеет отношения к вопросу, должна ли переменная указателя быть установлена ​​в NULL. Установка его в NULL - это хорошая практика на тех же основаниях, что чистка посуды после того, как вы поужинаете, это хорошая практика - хотя она не является защитой от всех ошибок, которые может иметь код, она способствует хорошему здоровью кода.
Франси Пенов
2
@ Франци Многие люди с тобой не согласны. А наличие копии, безусловно, имеет значение, если вы попытаетесь использовать копию после удаления оригинала.
3
Франци, есть разница. Вы чистите посуду, потому что используете ее снова. Вам не нужен указатель после его удаления. Это должно быть последним, что вы делаете. Лучше практиковаться в том, чтобы вообще избегать ситуации.
GManNickG
1
Вы можете повторно использовать переменную, но тогда это уже не случай защитного программирования; это как вы разработали решение проблемы под рукой. ОП обсуждает, стоит ли стремиться к этому защитному стилю, а не к тому, что мы когда-либо установим указатель на ноль. И в идеале, на ваш вопрос, да! Не используйте указатели после их удаления!
GManNickG
7

Если после кода больше delete , да. Когда указатель удаляется в конструкторе или в конце метода или функции, нет.

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

Еще лучшая практика - использовать интеллектуальные указатели (совместно используемые или с областью видимости), которые автоматически удаляют целевые объекты.

Томас Мэтьюз
источник
Все (в том числе и автор оригинального вопроса) согласны с тем, что умные указатели - это путь. Код развивается. Может быть больше кода после удаления, когда вы в первый раз исправите его, но это может измениться со временем. Помещение в задание помогает, когда это происходит (и в то же время почти ничего не стоит).
Эдриан Маккарти
3

Как уже говорили другие, delete ptr; ptr = 0;это не заставит демонов вылететь из вашего носа. Тем не менее, это поощряет использование в ptrкачестве своего рода флага. Код засоряется deleteи устанавливает указатель на NULL. Следующий шаг - разбросать if (arg == NULL) return;ваш код, чтобы защитить его от случайного использования NULLуказателя. Проблема возникает после проверкиNULL становятся вашими основными средствами проверки состояния объекта или программы.

Я уверен, что в коде есть какой-то запах использования указателя в качестве флага, но я его не нашел.

D.Shawley
источник
9
Нет ничего плохого в использовании указателя в качестве флага. Если вы используете указатель и NULLне является допустимым значением, тогда вам, вероятно, следует использовать ссылку.
Адриан Маккарти
2

Я немного изменю ваш вопрос:

Вы бы использовали неинициализированный указатель? Вы знаете, тот, который вы не установили в NULL или выделите память, на которую он указывает?

Существует два сценария, в которых установка указателя на NULL может быть пропущена:

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

Между тем, утверждение о том, что установка указателя на NULL может скрывать ошибки для меня, звучит как утверждение, что вы не должны исправлять ошибку, потому что исправление может скрывать другую ошибку. Единственные ошибки, которые могут отображаться, если указатель не установлен в NULL, будут те, которые пытаются использовать указатель. Но установка его в NULL фактически вызовет точно такую ​​же ошибку, как если бы вы использовали его с освобожденной памятью, не так ли?

Франси Пенов
источник
(A) «звучит как утверждение, что вы не должны исправлять ошибку» Не установка указателя на NULL не является ошибкой. (B) «Но установка его в NULL фактически вызовет точно такую ​​же ошибку». Нет. Установка в NULL скрывает двойное удаление . (C) Сводка: установка в NULL скрывает двойное удаление, но выставляет устаревшие ссылки. Не установка в NULL может скрывать устаревшие ссылки, но предоставляет двойное удаление. Обе стороны согласны с тем, что реальная проблема заключается в исправлении устаревших ссылок и двойных удалений.
Mooing Duck
2

Если у вас нет другого ограничения, которое заставляет вас устанавливать или не устанавливать указатель в NULL после удаления (одно из таких ограничений было упомянуто Нейлом Баттервортом ), тогда я лично предпочитаю оставить это так.

Для меня вопрос не "это хорошая идея?" но "какое поведение я бы помешал или позволил добиться успеха, делая это?" Например, если это позволяет другому коду увидеть, что указатель больше не доступен, почему другой код даже пытается просмотреть освобожденные указатели после их освобождения? Обычно это ошибка.

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

MSN
источник
2

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

Если это то, что вы на самом деле имеете в виду, лучше сделать это явно в источнике, используя что-то вроде boost :: option

optional<Foo*> p (new Foo);
// (use p.get(), but must test p for truth first!...)
delete p.get();
p = optional<Foo*>();

Но если вы действительно хотите, чтобы люди знали, что указатель «испортился», я согласен на 100% согласиться с теми, кто говорит, что лучше всего сделать так, чтобы он вышел из области видимости. Затем вы используете компилятор, чтобы предотвратить возможность неправильных разыменований во время выполнения.

Это ребенок во всей воде С ++, не должен выбрасывать его. :)

HostileFork говорит, что не доверяйте SE
источник
2

В хорошо структурированной программе с соответствующей проверкой ошибок нет причин не присваивать ей значение null.0в этом контексте выделяется как общепризнанное недействительное значение. Терпеть неудачу и терпеть неудачу скоро.

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

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

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

Оттуда у вас есть только очень ограниченная область действия и контекст, где может существовать нулевой указатель (или это разрешено).

То же самое может быть применено к указателям, которые не являются const . Отслеживание значения указателя является тривиальным, поскольку его область действия настолько мала, а неправильное использование проверяется и хорошо определяется. Если ваш инструментарий и инженеры не могут следовать программе после быстрого чтения, или если выполняется неправильная проверка ошибок или непоследовательный / мягкий ход программы, у вас есть другие, более серьезные проблемы.

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

джастин
источник
1

Позвольте мне расширить то, что вы уже положили в свой вопрос.

Вот что вы задали в своем вопросе в форме маркера:


Установка указателей на NULL после удаления не является универсальной хорошей практикой в ​​C ++. Есть моменты, когда:

  • это хорошо сделать
  • и времена, когда это бессмысленно и может скрывать ошибки.

Однако не бывает случаев, когда это плохо ! Вы не будете вносить больше ошибок, явно обнуляя их, вы не потеряете память, вы не вызовете неопределенного поведения .

Так что, если сомневаетесь, просто обнулите его.

Сказав это, если вы чувствуете, что должны явно обнулить некоторый указатель, то для меня это звучит так, как будто вы недостаточно разбили метод и должны рассмотреть подход рефакторинга под названием «Извлечь метод», чтобы разделить метод на отдельные части.

Лассе В. Карлсен
источник
Я не согласен с «не бывает случаев, когда это плохо». Подумайте о количестве резцов, которые вводит эта идиома. У вас есть заголовок, который включается в каждый блок, который что-то удаляет, и все эти местоположения удаления становятся чуть менее простыми.
GManNickG
Бывают времена, когда это плохо. Если кто-то попытается разыменовать ваш удаленный, теперь нулевой указатель, когда он не должен, он, вероятно, не потерпит крах, и эта ошибка будет «скрыта». Если они разыменуют ваш удаленный указатель, в котором все еще есть какое-то случайное значение, вы, вероятно, заметите, и ошибку будет легче увидеть.
Карсон Майерс
@Carson: Мой опыт совершенно противоположен: разыменование nullptr почти во всех случаях приводит к сбою приложения и может быть обнаружено отладчиком. Разыменование висячего указателя обычно не создает проблемы сразу, но часто приводит к неверным результатам или другим ошибкам в будущем.
MikeMB
@MikeMB Я полностью согласен, мои взгляды на это существенно изменились за последние ~ 6,5 лет
Карсон Майерс
С точки зрения программиста, мы все были кем-то другим 6-7 лет назад :) Я даже не уверен, что осмелился бы сегодня ответить на вопрос C / C ++ :)
Лассе В. Карлсен
1

Да.

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

Если вы этого не сделаете, однажды у вас будут неприятные ошибки разыменования указателя.

Я всегда использую макрос для удаления:

#define SAFEDELETE(ptr) { delete(ptr); ptr = NULL; }

(и аналогично для массива free (), освобождая дескрипторы)

Вы также можете написать методы «самостоятельного удаления», которые принимают ссылку на указатель вызывающего кода, поэтому они принудительно указывают указатель вызывающего кода на NULL. Например, чтобы удалить поддерево многих объектов:

static void TreeItem::DeleteSubtree(TreeItem *&rootObject)
{
    if (rootObject == NULL)
        return;

    rootObject->UnlinkFromParent();

    for (int i = 0; i < numChildren)
       DeleteSubtree(rootObject->child[i]);

    delete rootObject;
    rootObject = NULL;
}

редактировать

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

Есть также много способов, как вы могли бы реализовать вышесказанное - я просто пытаюсь проиллюстрировать идею принуждения людей к NULL-указателю, если они удаляют объект, вместо того, чтобы предоставить им средство для освобождения памяти, которая не NULL, указатель вызывающей стороны ,

Конечно, приведенный выше пример является лишь шагом к автоматическому указателю. Что я и не предлагал, потому что ОП специально спрашивал о том, чтобы не использовать автоматический указатель.

Джейсон Уильямс
источник
2
Макросы - плохая идея, особенно когда они выглядят как обычные функции. Если вы хотите сделать это, используйте шаблонную функцию.
2
Ух ты ... Я никогда не видел ничего подобного, чтобы anObject->Delete(anObject)лишить законной силы anObjectуказатель. Это просто страшно. Вы должны создать статический метод для этого, чтобы вы были вынуждены делать это TreeItem::Delete(anObject)как минимум.
Д.Шоули
Извините, набрал это как функцию, а не используя правильную заглавную форму "это макрос". Исправлено. Также добавили комментарий, чтобы объяснить себя лучше.
Джейсон Уильямс
И вы правы, мой быстро разбитый пример был мусором! Исправлена ​​:-). Я просто пытался придумать быстрый пример, чтобы проиллюстрировать эту идею: любой код, который удаляет указатель, должен гарантировать, что указатель установлен в NULL, даже если кто-то еще (вызывающий) владеет этим указателем. Поэтому всегда передавайте ссылку на указатель, чтобы его можно было принудительно установить в NULL в точке удаления.
Джейсон Уильямс
1

«Бывают моменты, когда это полезно, и времена, когда это бессмысленно и может скрывать ошибки»

Я вижу две проблемы: этот простой код:

delete myObj;
myobj = 0

делается для лайнера в многопоточной среде:

lock(myObjMutex); 
delete myObj;
myobj = 0
unlock(myObjMutex);

«Лучшая практика» Дона Нейфельда не всегда применима. Например, в одном автомобильном проекте мы должны были установить указатели на 0 даже в деструкторах. Я могу представить, что в программном обеспечении, критичном для безопасности, такие правила не редкость. Проще (и разумнее) следовать им, чем пытаться убедить команду / средство проверки кода для каждого использования указателя в коде, что строка, обнуляющая этот указатель, является избыточной.

Другая опасность - полагаться на эту технику в коде, использующем исключения:

try{  
   delete myObj; //exception in destructor
   myObj=0
}
catch
{
   //myObj=0; <- possibly resource-leak
}

if (myObj)
  // use myObj <--undefined behaviour

В таком коде вы либо создаете утечку ресурсов и откладываете проблему, либо происходит сбой процесса.

Итак, эти две проблемы, спонтанно возникающие в моей голове (Херб Саттер наверняка расскажет больше), делают для меня все вопросы типа «Как избежать использования умных указателей и безопасного выполнения работы с обычными указателями» как устаревшие.

Валентин Хайниц
источник
Я не вижу, как 4-линейный значительно сложнее, чем 3-линейный (в любом случае следует использовать lock_guards), и если ваш деструктор выбрасывает, у вас все равно проблемы.
MikeMB
Когда я впервые увидел этот ответ, я не понимал, почему вы хотите обнулить указатель в деструкторе, но теперь я понимаю - это для случая, когда объект, владеющий указателем, используется после его удаления!
Марк Рэнсом
0

Всегда есть о чем беспокоиться.

GrayWizardx
источник
1
Неужели так сложно поставить «висячие указатели» вместо «это»? :) По крайней мере, это дает вашему ответу некоторую субстанцию.
GManNickG
4
Это даже тема совета по W3C QA: «Не используйте« нажмите здесь »как текст ссылки»: w3.org/QA/Tips/noClickHere
outis
0

Если вы собираетесь перераспределить указатель перед тем, как снова его использовать (разыменовать его, передать в функцию и т. Д.), Сделать указатель NULL просто дополнительной операцией. Однако, если вы не уверены, будет ли он перераспределен или нет до его повторного использования, установка NULL - хорошая идея.

Как уже говорили многие, гораздо проще использовать умные указатели.

Редактировать: Как сказал Томас Мэтьюз в этом предыдущем ответе , если указатель удален в деструкторе, нет необходимости назначать ему значение NULL, поскольку он не будет использоваться снова, поскольку объект уже уничтожается.

Dustin
источник
0

Я могу представить, что установка указателя на NULL после удаления будет полезна в редких случаях, когда существует законный сценарий повторного использования его в одной функции (или объекте). В противном случае это не имеет смысла - указатель должен указывать на что-то значимое, пока оно существует - точка.

Неманья Трифунович
источник
0

Если код не относится к наиболее критичной к производительности части вашего приложения, сделайте его простым и используйте shared_ptr:

shared_ptr<Foo> p(new Foo);
//No more need to call delete

Он выполняет подсчет ссылок и является потокобезопасным. Вы можете найти его в tr1 (пространство имен std :: tr1, #include <memory>) или, если ваш компилятор не предоставляет его, получить его из boost.

beta4
источник