Существует ли установленное значение указателя для освобожденного указателя?

некоторые программисты любят устанавливать переменную указателя в null после освобождения указателя:

delete ptr;
ptr = 0;

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

есть ли альтернативное значение, которое я мог бы назначить переменной указателя, которая обозначает выпущенные указатели?

delete ptr;
ptr = SOME_MAGIC_VALUE;

В идеале, я бы хотел В Visual Studio 2008, чтобы сказать мне,"программа была прекращена, потому что вы пытались получить доступ к уже выпущенному указателю здесь!" в режиме отладки.


- ладно, кажется, я должен проверить сам. Что-то не так со следующим шаблоном?

template <typename T>
void sole_delete(T*& p)
{
    if (p)
    {
        delete p;
        p = 0;
    }
    else
    {
        std::cerr << "pointee has already been released!n";
        abort();
    }
}

12 ответов


нет. Тест для " 0 " при попытке delete что-то если вы действительно хотите предупредить или ошибка из-за этого.

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

редактировать да, люди я знаю C++ не требует тестирования вокруг delete 0;

Я не предлагаю if (ptr != 0) delete ptr;. Я предполагая if (ptr == 0) { some user error that the OP asked for } delete ptr;


назначение NULL после освобождения указатель. И прежде чем использовать его, Регистрация для своего NULLity.. Если значение равно null, сообщите об ошибке сами.


есть ли альтернативное значение, которое я мог бы назначить переменной указателя, которая обозначает выпущенные указатели?

В идеале, я хотел бы, чтобы Visual Studio 2008 сказал мне: "программа была прекращена, потому что вы пытались получить доступ к уже выпущенному указателю здесь!"в режиме отладки.

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

в любом случае, я не думаю, что у меня есть написано ptr = NULL более нескольких раз за последнее десятилетие. Зачем мне это делать? Такой указатель, безусловно, скрыт внутри объекта, деструктор которого удалит объект, на который он ссылается, и после вызова деструктора указатель также исчезнет.

и если некоторые обстоятельства потребуют, чтобы я оставил указатель, чтобы болтаться после удаления указателя, я бы не установил его в NULL просто так я хочу, чтобы код, чтобы crash ASAP, если бы я дважды удалил. Установка указателя на NULL просто маски ошибка.

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


нет, называя delete на нулевом указателе совершенно нормально с точки зрения C++. Присвоение некоторого магического значения серьезно нарушит код - теперь вам придется различать нулевые указатели, действительные указатели и волшебное значение указатели, и я думаю, что это будет огромный беспорядок.

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


Если вы просто хотите проверить распределения и удаления, самый простой способ-написать свой собственный глобальный operator new и operator delete и вручную отслеживать все указатели, которые выделены и освобождены.

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

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

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


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

Не неправильно вызывать delete несколько раз на одном указателе (переменной) только на то, что он указывает к.

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

T * array[N];
for( i = 0; i < N; ++ i )
{
   array[i] = new T;
}
T* ptr;
for( i = 0; i < N; ++i )
{
  ptr = array[i];
  delete ptr;
}

и помимо того, что это не лучший способ сделать что-то, я вызываю delete для переменной "ptr" несколько раз, но по разным адресам и явно не ошибка.


Я думаю sharptooth уже предоставлен действительный ответ, но я думаю, что он не смог четко сформулировать это:

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


отвечая на вопрос в вопросе[sic].

нет, нет установленного значения для выпущенных указателей.

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

edit: конец ответа на оригинальный вопрос; бессвязный о double-delete

Это действительно зависит от конструкции если delete on NULL ошибка ждать, что произойдет. Во многих случаях это не так. Возможно, вам следует использовать "безопасное удаление", когда это необходимо - или во время отладки? Вот так:

template <typename T>
void safe_delete(T*& ptr)
{
  if (ptr == 0)
    throw std::runtime_error("Deleting NULL!");
  delete ptr;
  ptr = 0;
}

нет смысла.

Я не буду вступать в явно довольно горячий разговор, просто укажите на очевидный факт:указатели передаются copy.

с некоторым кодом он дает:

T* p = /* something */;
T* q = p;

delete q;
q = 0;

вы чувствуете себя в безопасности ?

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

Это как затыкать отверстие в сите и надеяться, что это остановит вода из льющейся.


В C++0x вы можете

delete ptr;
ptr = nullptr;

установка указателя на определенное значение повлияет только на эту копию указателя, поэтому она не обеспечивает почти никакой защиты. Если программа должна быть проверяемо правильной, есть классы интеллектуальных указателей, которые отслеживают копии указателя и аннулируют их, иначе я бы просто рекомендовал такой инструмент, как Valgrind (в Linux) или Rational Purify (в Windows), который позволит вам проверить ошибки доступа к памяти.


Это не ошибка delete nullpointer; по определению он ничего не делает.

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

как правило, обнуление указателей принадлежит, на мой взгляд, со всеми остальными'isms Microsoft, таких как Венгерская нотация и широкое использование макросов.

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

однако, сказав это, для человека, который склоняется к ультра-формально педантичному, это может быть, по крайней мере, эмоционально удовлетворительная идея нулевых указателей, например, a std::vector, после delete. Причина в том, что Священный стандарт ISO / IEC 14882 позволяет std::vector деструктор, чтобы делать довольно нечестивые вещи, такие как копирование значений указателя вокруг. И в формально педантичном представлении даже такое копирование недопустимых значений указателя вызывает неопределенность Поведение. Это не имеет практического значения. Во-первых, я не знаю абсолютно никакой современной платформы, где копирование имело бы какой-либо вред, а во-вторых, так много кода полагается на стандартные контейнеры, которые ведут себя разумно, что они просто должны: иначе никто не будет использовать такую реализацию.

Cheers & hth.