Как понять, что в C ++ удален указатель

Когда я пишу такой код, он печатает «не удалено». Как я могу на 100% убедиться, удален указатель или нет?

int* a = new int;
*a = 5;
delete a;

if (!a)                      //I also tried a == NULL but got same result     
    cout<<"deleted"<<endl;
else
    cout<<"not deleted"<<endl;

person ibrahim    schedule 27.12.2011    source источник
comment
Вы можете установить для a значение null после удаления, чтобы обозначить, что теперь он недействителен, хотя это бывает редко.   -  person Pubby    schedule 28.12.2011


Ответы (7)


Вы не можете. Не забудьте избавиться от всех копий указателя, когда вы delete его, так как место в памяти, на которое ссылается указатель, вероятно, позже будет повторно использовано для других данных.

person Community    schedule 27.12.2011
comment
Первый полезный ответ, который я видел на такой вопрос. Если вы не избавитесь от копий, некоторые реализации C ++ будут пытаться delete снова указать указатель при выходе из программы. - person Trevor Jex; 11.06.2018

вызов delete для указателя не устанавливает сам указатель в NULL (зачем это нужно? Вы поймете, что он не может этого сделать, учитывая подпись delete, т.е. он принимает void*, а не void**).

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

person Ed S.    schedule 27.12.2011
comment
Что еще более важно, он не меняет никаких псевдонимов. - person Joel; 28.12.2011
comment
Мне нужно проверить узел дерева, который я реализую для своего hw, удален или нет? - person ibrahim; 28.12.2011
comment
@ibrahim: Тебе не нужно. Когда вы удаляете / удаляете узел из дерева, тогда окружающие узлы должны быть изменены для соединения друг с другом на своем месте. Вы, конечно, можете явно установить для него значение NULL, но я не понимаю, зачем вам это нужно. - person Ed S.; 28.12.2011
comment
Вы поймете, что этого не могло быть - этого не следует, потому что delete - оператор. Операторы, конечно, могут изменять свои операнды. Страуструп заявляет в своем FAQ по C ++, что delete разрешено устанавливать операнды lvalue равными нулю, хотя я не вижу ничего в стандарте, чтобы поддержать его утверждение. Может, это досадная штука. - person Steve Jessop; 28.12.2011
comment
@SteveJessop, не могли бы вы дать ссылку на упомянутый пункт часто задаваемых вопросов Страуструпа? - person Ivan Aksamentov - Drop; 15.08.2015

Вы не «удаляете» указатель, вы удаляете то, что он адресует.

person Hot Licks    schedule 27.12.2011

Организуйте свой код следующим образом:

{
    int* a = new int;
    *a = 5;
    delete a;
}
// a no longer exists so you know it is gone.

PS. Предпочитайте никогда не использовать указатели RAW.

{
   // C++03
   std::auto_ptr<int> a(new int);
   *a = 5;
}

Or

{
   // C++11
   std::unique_ptr<int> a(new int);
   *a = 5;
}
person Martin York    schedule 27.12.2011

Удаление указателя не установит его в NULL, оно удалит память, на которую указывает указатель. Даже если вы исследуете память, вы не сможете понять, свободна она или нет. Другими словами, проверить, указывает ли указатель на «доступную» память, непросто, и уж точно не так просто, как a == NULL.

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

int* a = new int;
*a = 5;
delete a;
a = NULL;

if (!a)                      //I also tried a == NULL but got same result     
    cout<<"deleted"<<endl;
else
    cout<<"not deleted"<<endl;
person Kashyap    schedule 27.12.2011
comment
Это скрывает другие ошибки в коде. Лучше не делать этого и обнаруживать эти ошибки во время тестирования. - person Martin York; 28.12.2011
comment
@LokiAstari Например .....? - person Kashyap; 28.12.2011
comment
Есть еще проблемы с этой стратегией. Самый простой - это создание копии a (int* b = a), а затем удаление a. b по-прежнему имеет тот же адрес, но теперь он недействителен и не имеет значения NULL, и OP по-прежнему будет сталкиваться с теми же проблемами при тестировании с b. Но это, конечно, надуманный пример. - person Marlon; 28.12.2011
comment
Проблема в том, что это не дает реальной пользы. Тем не менее, он скрывает другие типы ошибок, которые потенциально могут быть исправлены. Таким образом, лучше этого не делать. Лучшая стратегия - не попасть в такую ​​ситуацию и позволить указателям выпасть из области видимости после того, как они были удалены. - person Martin York; 28.12.2011
comment
'установите указатель в NULL, как только вы освободите память, на которую он указывает:' .. если вы сразу не перезаписываете его другим допустимым указателем или, возможно, по другим причинам, чтобы не устанавливать его в NULL. - person Martin James; 28.12.2011
comment
Кодирование @LokiAstari, при котором указатели выпадают из области видимости в конце использования, выполнить сложнее, чем указано. Повторное использование переменных (за неимением лучшего слова) - одно из основных применений указателя. ИМХО. - person Kashyap; 27.02.2012
comment
@thekashyap: Если вы пишете C, возможно (но я в этом сомневаюсь). В C ++ это стандартно, и я бы никогда не использовал переменную повторно. Вот почему у нас есть компиляторы. - person Martin York; 27.02.2012

Почему бы не использовать valgrind для экспериментального «доказательства» отсутствия утечек памяти в приложении - доказательства того, что все узлы были удалены, а их содержимое удалено?

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

person Nick Westlake    schedule 27.12.2011

Простой факт заключается в следующем: C ++ - небезопасный язык.

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

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

Если вы создаете структуру данных, вам решать, насколько безопасной должна быть эта структура данных. Обратите внимание, что структуры данных стандартной библиотеки C ++ позволяют итераторам (обобщенным указателям) становиться недействительными при определенных условиях. Это возлагает на пользователя ответственность знать, что они делают.

Выигрыш от этого - высокая производительность. Если вам не нужна такая производительность, вам нужно использовать более безопасный контейнер или структуру данных. Если вам нужна такая безопасность, вам следует использовать умный указатель для элементов в вашей структуре данных. Пользователь должен получить shared_ptr<> или weak_ptr<> объекты, которые ссылаются на узлы, а не на голые указатели. И так далее.

C ++ небезопасен. Конечно, это небезопасно; это C ++. Но это хорошо.

person Nicol Bolas    schedule 27.12.2011