Почему мне нужно удалить []?

Скажем, у меня есть такая функция:

int main()
{
    char* str = new char[10];

    for(int i=0;i<5;i++)
    {
        //Do stuff with str
    }

    delete[] str;
    return 0;
}
  • Почему мне нужно удалить str, если я все равно закончу программу? Мне было бы безразлично, если эта память пойдет на землю, полную единорогов, если я просто собираюсь выйти, верно?

  • Это просто хорошая практика?

  • Есть ли у него более глубокие последствия?

Ответ 1

Если на самом деле ваш вопрос на самом деле: "У меня есть эта тривиальная программа, нормально ли, что я не освобожу несколько байтов, прежде чем она выйдет?" ответ - да, это хорошо. В любой современной операционной системе это будет прекрасно. И программа тривиальна; это не похоже на то, что вы собираетесь положить его в кардиостимулятор или запустить тормозную систему Toyota Camry с этой штукой. Если единственным клиентом является то, что вы единственный, на кого вы можете повлиять, будучи неаккуратным, вы.

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

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

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

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

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

У меня такой же долговременный сервис. Если я обнаруживаю, что одна из моих внутренних структур данных повреждена, я хочу "быстро выйти из строя". Программа находится в состоянии undefined, она, скорее всего, работает с повышенными привилегиями, и я собираюсь предположить, что если я обнаруживаю поврежденное состояние, это потому, что мой сервис активно атакуется враждебными сторонами. Самое безопасное, что нужно сделать, - немедленно закрыть службу. Я предпочел бы, чтобы злоумышленники отказали в обслуживании клиентов, а не рискуя остаться в стороне от обслуживания и скомпрометировать данные моих пользователей. В этом сценарии аварийного отключения я должен убедиться, что каждый байт памяти, которую я выделил, освобожден?

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

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

Ответ 2

Да, это хорошая практика. Вы НИКОГДА не должны предполагать, что ваша ОС позаботится о освобождении памяти, если вы займетесь этой привычкой, она в дальнейшем вас повредит.

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

Ответ 3

Важное замечание: delete освобождение памяти - почти просто побочный эффект. Важная вещь, которую он делает, - уничтожить объект. С дизайнами RAII это может означать что угодно: закрывать файлы, освобождать дескрипторы ОС, завершать потоки или удалять временные файлы.

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

В вашем примере нет причины НЕ называть delete. но нет причин для вызова new, так что вы можете обойти проблему таким образом.

char str[10];

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

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

Но это не всегда легко: обходные пути для статического инициализационного порядка фиаско часто означают, что у вас нет выбора, кроме как полагаться на ОС, очищающую несколько синглтон- типа для вас.

Ответ 4

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

(не то, что я не согласен с причинами в "Да", я просто думаю, что есть аргументы в обоих направлениях)

Ответ 5

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

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

Ответ 6

new и delete являются зарезервированными ключевыми словами. Они должны взаимодействовать друг с другом через кодовый блок или через родительский объект lifecyle. Когда младший брат совершает ошибку (new), старший брат захочет очистить (delete) его. Тогда мать (ваша программа) будет счастлива и гордиться ими.

Ответ 7

Я не могу больше согласиться с Эриком Липпертом:

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

Другие ответы здесь предоставили аргументы для и против обоих, но реальная суть вопроса , что делает ваша программа. Рассмотрим более нетривиальный пример, в котором экземпляр типа, который динамически выделяется, является пользовательским классом, а деструктор класса выполняет некоторые действия, которые вызывают побочный эффект. В такой ситуации аргумент утечки памяти или нет тривиально, тем более важной проблемой является то, что неспособность вызвать delete на такой экземпляр класса приведет к поведению Undefined.

[basic.life] 3.8 Срок жизни объекта
Параграф 4:

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

Итак, ответ на ваш вопрос: как говорит Эрик, "зависит от того, что делает ваша программа"

Ответ 8

Это справедливый вопрос, и есть несколько вещей, которые следует учитывать при ответе:

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

Ответ 9

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

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

Это также плохая эстетика, многие разработчики будут смотреть на незакрепленную "str" и чувствовать легкую тошноту: (

Ответ 10

У вас много ответов на профессиональный опыт. Здесь я говорю наивный, но ответ, который я рассматривал как факт.

  • Резюме

    3. Есть ли у него более глубокие последствия?

    A: Ответ будет достаточно подробно.

    2. Это просто хорошая практика?

    A: Это считается хорошей практикой. Освободите ресурсы/память, которые вы получили, когда вы уверены в этом, больше не используются.

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

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

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

    Q: Это зависит от того, что делает программа?

    A: Если уничтоженная вселенная была приемлемой, то нет. Тем не менее, программа может работать некорректно, как ожидалось, и даже быть программой, которая не выполняет то, что она должна. Вы можете серьезно подумать о том, почему вы строите такую ​​программу?

    Q: Это зависит от того, насколько сложна программа?

    A: Нет. См. пояснение.

    Q: От этого зависит стабильность программы?

    A: Близко.

    И я считаю, что это зависит от

    • Какая вселенная программы?
    • Как ожидалось, что программа выполнила свою работу?
    • Сколько стоит программа для других, и вселенная, где она находится?

      О термине Вселенная, см. Пояснение.

    Для сводки, это зависит от того, о чем заботятся вы.


  • Объяснение

    Важно: Если мы определяем термин program как функцию, то его юниверс - это приложение. Есть много деталей, опущенных; как идея для понимания, это достаточно долго.

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

    9RJKM.gif

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

    mjLai.jpg

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

    Важно, чтобы среда выполнения отвечала как ОС, так и приложениям, но последняя имеет более важное значение. Время выполнения - это вселенная приложений, если она уничтожает все запущенные под ней приложения, исчезла.

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

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

    Как упоминалось выше, среда выполнения также несет ответственность перед ОС. левый круг на следующей диаграмме выглядит так.

    ScsZs.jpg

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

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

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

Ответ 11

Зачем мне удалять str, если я собираюсь закончить программу?

Потому что вы не хотите лениться...

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

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

Это просто хорошая практика?

Это справедливо хорошая практика.

Есть ли у него более глубокие последствия?

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

Поместите конструкцию цикла while (1) вокруг вашего кода без удаления. Сложность кода не имеет значения. Утечки памяти связаны с временем процесса.

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

int main()
{

    while(1)
    { 
        char* str = new char[10];

        for(int i=0;i<5;i++)
        {
            //Do stuff with str
        }
    }

    delete[] str;
    return 0;
}

Ответ 12

ТЕХНИЧЕСКИЙ, программист не должен полагаться на ОС, чтобы что-то делать. Таким образом, ОС не требуется для восстановления потерянной памяти.

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

Источник: Распределение и мифы GC (оповещение PostScript!)

Allocation Myth 4: Non-garbage-collected programs should always
deallocate all memory they allocate.

The Truth: Omitted deallocations in frequently executed code cause
growing leaks. They are rarely acceptable. but Programs that retain
most allocated memory until program exit often perform better without
any intervening deallocation. Malloc is much easier to implement if
there is no free.

In most cases, deallocating memory just before program exit is
pointless. The OS will reclaim it anyway. Free will touch and page in
the dead objects; the OS won't.

Consequence: Be careful with "leak detectors" that count allocations.
Some "leaks" are good!
  • Я считаю очень плохой практикой использовать malloc/new без вызова free/delete.

  • Если память все равно будет исправлена, какой вред может быть явным освобождением, когда вам нужно?

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

Сказав это, я рекомендую вам использовать бесплатный /delete.


Если вы привыкнете к этой привычке, кто скажет, что однажды вы случайно не примените этот подход, это важно?


Всегда нужно освобождать ресурсы после того, как с ними делается, будь то файловые дескрипторы/память/мьютексы. Имея эту привычку, никто не ошибается при создании серверов. Ожидается, что на некоторых серверах будет работать 24x7. В таких случаях любая утечка любого типа означает, что ваш сервер в конечном итоге исчерпает этот ресурс и каким-то образом зависает. Короче говоря, полезная программа, и утечка не так уж плоха. Любой сервер, любая утечка - смерть. Сделай себе одолжение. Очистите себя. Это хорошая привычка.


Think about your class 'A' having to deconstruct. If you don't call
'delete' on 'a', that destructor won't get called. Usually, that won't
really matter if the process ends anyway. But what if the destructor
has to release e.g. objects in a database? Flush a cache to a logfile?
Write a memory cache back to disk? **You see, it not just 'good
practice' to delete objects, in some situations it is required**. 

Ответ 13

Еще одна причина, о которой я еще не упоминал, заключается в том, чтобы сделать чистые и более тихие результаты использования статических и динамических инструментов анализатора (например, valgrind или Coverity). Чистая производительность с нулевыми утечками памяти или нулевыми сообщениями означает, что при всплывании новой записи ее легче обнаружить и исправить.

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

Ответ 14

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

Ответ 15

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

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

Я лично считаю плохую практику полагаться на ОС, чтобы освободить вашу память (хотя это и будет сделано), причина в том, что если позже вам придется интегрировать свой код с более крупной программой, вы будете тратить часы на отслеживание и исправление памяти утечки!

Итак, уберите свою комнату перед отъездом!