Гарантирует ли указатель сохранение своего значения после `delete` в C ++? - PullRequest
16 голосов
/ 15 февраля 2011

Вдохновлен этим вопросом .

Предположим, в коде C ++ у меня есть правильный указатель и правильно delete его. Согласно стандарту C ++ указатель станет недействительным (3.7.3.2/4 - функция освобождения сделает недействительными все указатели, относящиеся ко всем частям освобожденного хранилища ).

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

Гарантирует ли стандарт, что указатель сохранит свое значение или значение может быть изменено?

Ответы [ 7 ]

19 голосов
/ 15 февраля 2011

Нет, это не гарантировано, и реализация может законно присвоить ноль для lvalue операнда delete.

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

http://www.stroustrup.com/bs_faq2.html#delete-zero

10 голосов
/ 15 февраля 2011

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

delete p + 0;
3 голосов
/ 15 февраля 2011

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

2 голосов
/ 15 февраля 2011

Подпись глобального оператора delete, как того требует стандарт 3.7.3.2/2:

Каждая функция освобождения должна возвращать void, а ее первый параметр должен быть void *.

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

1 голос
/ 28 июля 2018

Этот вопрос важен! Я видел, что Visual Studio 2017 изменил значение указателя после «удаления». Это вызвало проблему, потому что я использовал инструмент трассировки памяти. Инструмент собирал указатели после каждого оператора «new» и проверял их после «delete». Псевдокод:

Data* New(const size_t count)
{
    Data* const ptr(new Data[count]);
    #ifdef TEST_MODE
    DebugMemory.Collect(ptr);
    #endif
    return ptr;
}

void Delete(Data* const ptr)
{
    delete[] ptr;
    #ifdef TEST_MODE
    DebugMemory.Test(ptr);
    #endif
}

Этот код хорошо работает в Visual Studio 2008, но не работает в Visual Studio 2017, поэтому я изменил порядок операций во второй функции.

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

1 голос
/ 15 февраля 2011

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

Вы не можете проверить ненулевое значение после delete, поэтому вопрос в целом бессмысленно .

Кроме того, аргумент delete может быть выражением rvalue, поэтому вопрос не имеет смысла.

Cheers & hth.,

1 голос
/ 15 февраля 2011

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

Возможно, вы задаетесь вопросом:вы делали свою собственную проверку на утечку, поэтому вы написали функцию для удаления указателя с карты после того, как вы сделали удаление.Это будет использовать std :: less, который гарантированно будет работать с указателями, которые не указывают в пределах диапазона, и предположительно будет работать также с указателями, которые указывают на недопустимую память.

Конечно, вы можетесбор мусора для «удаления» непосредственно перед удалением памяти, на которую оно указывало.

Как и в случае со стандартом, если значение, которое вы передаете для удаления, не является l-значением, оно гарантированно сохраняетсято же значение, но если это l-значение, оно определяется реализацией.

...