что такое роль удаления в распределении динамической памяти в C ++? [Дубликат]

25
задан Brian Tompsett - 汤莱恩 4 July 2015 в 13:34
поделиться

13 ответов

Может ли доступ к данным из-за ожидаемой могилы?

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

73
ответ дан dirkgently 15 August 2018 в 19:07
поделиться
  • 1
    Кроме того, полезно добавить следствие этого факта ... Если бы были данные, которые являются «чувствительными», хранящиеся в памяти, следует подумать, что это хорошая практика, чтобы полностью перезаписать его перед удалением (чтобы не допустить доступа к другим сегментам кода). – Romain 18 December 2009 в 21:37
  • 2
    Это должно быть обработано до вызова дент. – dirkgently 18 December 2009 в 21:44
  • 3
    ... или, по крайней мере, в дторе. – dirkgently 18 December 2009 в 21:46
  • 4
    @dirkgently: Да, я думаю, что деструктор - правильное место. Вы не хотите делать это слишком рано, и вы не можете сделать это слишком поздно. – David Thornley 18 December 2009 в 22:16
  • 5
    @Romain: Просто нужно убедиться, что он не оптимизирован, так как это не наблюдаемое поведение . (Используйте функцию API, которая не должна быть обрезана, не memset.) – Deduplicator 26 September 2014 в 09:19

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

Если вы хотите сделать его нулевым, выполните:

SingleBlock::~SingleBlock()

{    x = y = 0 ; }
0
ответ дан Ashish 15 August 2018 в 19:07
поделиться

После удаления объекта не определено, что произойдет с содержимым памяти, которое оно заняло. Это означает, что эта память может быть повторно использована повторно, но реализация не должна перезаписывать данные, которые были там изначально, и она не должна повторно использовать память сразу.

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

1
ответ дан CB Bailey 15 August 2018 в 19:07
поделиться

Да, этого можно ожидать время от времени. В то время как new резервирует место для данных, delete просто делает недействительным указатель, созданный с помощью new, позволяя записывать данные в ранее зарезервированных местах; он не обязательно удаляет данные. Однако вы не должны полагаться на это поведение, поскольку данные в этих местах могут меняться в любое время, что может привести к неправильной работе вашей программы. Вот почему после использования delete указателя (или delete[] в массиве, выделенном с помощью new[]), вы должны назначить ему NULL, чтобы вы не могли вмешиваться в неправильный указатель, если вы не будете выделите память с помощью new или new[] перед повторным использованием этого указателя.

0
ответ дан Dustin 15 August 2018 в 19:07
поделиться
  • 1
    В стандарте языка C ++ нет ничего, что предотвращало удаление delete памяти, которая была удалена или заполнена странным значением. Это реализация определена. – Thomas Matthews 18 December 2009 в 21:32

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

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

3
ответ дан Fred 15 August 2018 в 19:07
поделиться
  • 1
    Если компилятор может определить, что код неизбежно собирается получить доступ (даже посмотреть) к части доски, которую он не имеет, такое определение освободит компилятор от законов времени и причинности; некоторые компиляторы используют это так, что это было бы абсурдно десять лет назад (многие из которых до сих пор абсурдны, ИМХО). Я мог понять, что если два фрагмента кода не зависят друг от друга, компилятор может чередовать свою обработку любым способом, даже если это заставляет UB ударять «рано», но как только UB становится неизбежным, все правила вылетают из окна. – supercat 19 April 2015 в 23:08

Система не очищает память при отпускании ее через delete(). Таким образом, содержимое остается доступным, пока память не будет назначена для повторного использования и перезаписана.

2
ответ дан George Stocker 15 August 2018 в 19:07
поделиться

Он еще не будет обнулять ноль / менять память ... но в какой-то момент ковер будет вытаскиваться из-под ваших ног.

Нет, это, конечно, не предсказуемо: это зависит от как быстро распределяется память / освобождение памяти.

0
ответ дан jldupont 15 August 2018 в 19:07
поделиться

Удалить ничего не удаляет - он просто отмечает, что память «свободна для повторного использования». До тех пор, пока некоторые другие вызовы выделения не будут зарезервированы и заполнят это пространство, у него будут старые данные. Однако, полагаясь на то, что это большой нет-нет, в основном, если вы удаляете что-то забыть об этом.

Один из методов в этом отношении, который часто встречается в библиотеках, - это функция Delete:

template< class T > void Delete( T*& pointer )
{
    delete pointer;
    pointer = NULL;
}

Это предотвращает случайный доступ к недопустимой памяти.

Обратите внимание, что вполне нормально называть delete NULL;.

8
ответ дан Kornel Kisielewicz 15 August 2018 в 19:07
поделиться
  • 1
    Даже если вы не используете макрос, рекомендуется установить указатель на NULL сразу же после его освобождения. Это хорошая привычка проникать, предотвращая подобные недоразумения. – Mark Ransom 18 December 2009 в 21:37
  • 2
    @Kornel Любая библиотека C ++, которая использовала такой макрос, была бы чрезвычайно подозрительной, ИМХО. В самом лизинге это должна быть встроенная функция шаблона. – user 18 December 2009 в 21:43
  • 3
    @Mark Настройка указателей на NULL после удаления не является универсальной хорошей практикой в ​​C ++. Бывают моменты, когда это хорошо, и времена, когда это бессмысленно и может скрыть ошибки. – user 18 December 2009 в 21:44
  • 4
    Я ненавижу эту практику. Это очень захламляет, и меня. – GManNickG 18 December 2009 в 21:57
  • 5
    «Это предотвращает случайный доступ к недопустимой памяти». Это неверно, и это демонстрирует, почему использование этого трюка следует ожидать, чтобы он коррелировал с написанием плохого кода. char *ptr = new char; char *ptr2 = ptr; Delete(ptr); *ptr2 = 0;. Я случайно получил недопустимую память. Это просто путаное мышление, чтобы обнулить reference , полагая, что это защищает объект . Кроме того, не забывайте, что вам понадобится отдельная версия этой функции для указателей на массивы. – Steve Jessop 18 December 2009 в 22:25

Может ли доступ к данным из-за ожидаемой могилы?

В большинстве случаев да. Вызов delete не обнуляет память.

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

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

30
ответ дан Martin 15 August 2018 в 19:07
поделиться
  • 1
    Однако нет гарантии, что new или malloc не будут выделять некоторые новые объекты поверх старых. Другой катастрофой может быть сборщик мусора системы. Кроме того, если вашей программе предоставляется память из общесистемного пула памяти, другие программы могут записывать данные призрака. – Thomas Matthews 18 December 2009 в 21:29
  • 2
    Вообще-то, нет. Успешный доступ к удаленной памяти не ожидается, это неопределенное поведение. Еще одно распределение может также легко переписать память, которую вы только что освободили. – Curt Nichols 18 December 2009 в 21:31
  • 3
    @Thomas Matthews Я не говорю, что это хорошая идея, пытаясь получить к нему доступ. @ Курт Николс Это играет со словами. В зависимости от того, какой компилятор вы используете, вы можете ожидать , что память не обнуляется сразу при вызове delete. Вы, очевидно, не можете быть уверены в этом. – Martin 18 December 2009 в 21:34

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

1
ответ дан Ramónster 15 August 2018 в 19:07
поделиться

Ну, я тоже долго об этом задумывался, и я попытался провести несколько тестов, чтобы лучше понять, что происходит под капотом. Стандартный ответ заключается в том, что после вызова delete вы не должны ожидать ничего хорошего от доступа к этому месту памяти. Однако этого мне не показалось. Что на самом деле происходит при вызове delete (ptr) ? Вот что я нашел. Я использую g ++ на Ubuntu 16.04, так что это может сыграть роль в результатах.

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

Память, выпущенная с помощью delete , по-прежнему кажется выделенной программе, в которую она сначала выделила ее с помощью новый . Я пробовал, и уменьшение использования памяти после вызова delete . У меня было программное обеспечение, которое вырезало около 30 МБ списков через новые вызовы , а затем выпустило их с последующими вызовами delete . Случилось так, что, глядя на монитор системы во время работы программы, даже длительный сон после вызова delete , потребление памяти моей программы было одинаковым. Никакого снижения! Это означает, что delete не освобождает память системы.

На самом деле, похоже, что память, выделенная программой, является его вечно! Тем не менее, дело в том, что при освобождении памяти память может снова использоваться одной программой без необходимости выделять ее. Я попытался выделить 15 МБ, освободив их, а затем выделив еще 15 МБ данных, а программа никогда не использовала 30 МБ. Системный монитор всегда показывал его около 15 МБ. То, что я делал по отношению к предыдущему тесту, заключалось в том, чтобы изменить порядок, в котором все произошло: половина распределения, половина освобождения, другая половина распределения.

Итак, память, используемая программой, может увеличиваться, но никогда не сжиматься. Я думал, что, возможно, память действительно будет выпущена для других процессов в критических ситуациях, например, когда больше нет памяти. В конце концов, какой смысл это сделать, чтобы программа сохраняла свою собственную память навсегда, когда другие процессы просят об этом? Поэтому я снова выделил 30 МБ, и, освободив их, я запустил memtester с такой физической памятью, сколько мог. Я ожидал увидеть, что мое программное обеспечение передает свою память memtester. Но догадаться, этого не произошло!

Я составил короткий скринкаст, который показывает, что в действии:

Чтобы быть на 100% честным, возникла ситуация, когда произошло что-то . Когда я попробовал memtester с большей доступной физической памятью в середине процесса освобождения моей программы, память, используемая моей программой, упала примерно до 3 МБ. Процесс memtester был убит автоматически, хотя и что произошло еще более удивительно! Использование памяти моей программы увеличилось с каждым вызовом на удаление! Это было похоже на то, что Ubuntu восстанавливает всю память после инцидента с memtester.

Взято из http://www.thecrowned.org/c-delete-operator-really- frees-memory

0
ответ дан Ste_95 15 August 2018 в 19:07
поделиться

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

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

0
ответ дан Toby Speight 15 August 2018 в 19:07
поделиться

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

9
ответ дан user 15 August 2018 в 19:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: