Из того, что я понимаю, в стандартном С++ всякий раз, когда вы используете новый оператор, вы также должны использовать оператор delete в какой-то момент, чтобы предотвратить утечку памяти. Это связано с тем, что в С++ нет сборки мусора. В сборке мусора .NET автоматически, поэтому нет необходимости беспокоиться об управлении памятью. Правильно ли я понимаю? Спасибо.
Автоматическая сборка мусора в стандартном С++?
Ответ 1
Долгий ответ на этот вопрос заключается в том, что каждый раз, когда вызывается new
, где-то, как-то, должно быть вызвано delete
или какая-то другая функция освобождения (зависит от распределителя памяти и т.д.)
Но вам не нужно быть тем, кто предоставляет вызов delete
:
- Существует сборка мусора для С++, в виде Hans-Boehm Garbage Collector. Существуют также, вероятно, другие библиотеки сбора мусора.
- Вы можете использовать интеллектуальные указатели, которые используют RAII (и подсчет ссылок, если указатель обеспечивает общий доступ), чтобы определить, когда нужно удалить объект. Хорошей интеллектуальной библиотекой указателей является Boost умный указатель. Умные указатели в подавляющем большинстве случаев могут заменить исходные указатели.
- Некоторые фреймворки приложений, такие как Qt, строят деревья объектов таким образом, чтобы родительские отношения родительских отношений были выделены для выделенных объектов. В результате все необходимо для вызова
delete
на объект, и все его дети будут автоматически такжеdelete
d.
Если вы не хотите использовать какой-либо из этих методов, чтобы защитить от утечек памяти, вы можете попробовать использовать инструмент проверки памяти. Valgrind особенно хорош, хотя он работает только с Linux
Что касается .NET, да, выделение с помощью gcnew
означает, что память отслеживается .NET, поэтому никаких утечек. Другие ресурсы, такие как дескрипторы файлов и т.д., Не управляются GC.
Ответ 2
Ваше утверждение о новом операторе абсолютно правильно... но это упрощает семантику С++ совсем немного.
В С++ объекты могут быть созданы в стеке или в куче:
class Foo {};
int main() {
Foo obj1;
Foo* obj2 = new Foo();
delete obj2;
}
В приведенном выше примере obj1 создается в стеке, а obj2 создается в куче (с новым). Объекты, созданные в куче, не уничтожаются до тех пор, пока на них явно не будет вызвано удаление. Однако объекты в стеке автоматически уничтожаются, когда они выходят из области видимости (т.е. Когда main() возвращает в этом примере).
Это позволяет использовать идиому "Инициализация ресурсов" (a.k.a. RAII) на С++, которая намного мощнее базовой сборки мусора. Ресурсы, которые необходимо очистить (память кучи, сокеты, файлы, соединения БД и т.д.), Обычно помещаются в объекты на основе стека, деструкторы которых заботятся о очистке.
Напротив, Java и С# не позволяют создавать объекты в стеке и не гарантируют, что коллекция когда-либо случится, и что финализаторы будут работать (я не парень из С#, поэтому я могу быть немного неправильно там). Поэтому, когда вы получаете свободное управление памятью кучи в Java/С#, на самом деле вы получите намного больше кода очистки ресурсов на этих языках, чем на С++.
Ответ 3
В idiomatic на высоком уровне С++, вы никогда не вызываете delete.
С++ не имеет стандартного сборщика мусора, который работает так же, как и на С#, и поэтому верно, что в принципе new
и delete
необходимо спарить. Однако в С++ есть механизмы, которые полностью исключают явное использование delete
для кода, написанного в современном стиле.
Первое, что нужно отметить, это то, что в С++ вы используете new
гораздо реже, чем используете new
в С#. Это связано с тем, что в С# вы используете new
всякий раз, когда вы создаете экземпляр структуры, класса или массива, но на С++ вы используете new
только тогда, когда хотите динамически управлять элементом данных. Большинство данных на С++ не требуют динамического управления и поэтому могут быть созданы без использования new
. [Иначе говоря, new
имеет другое значение в С#, чем в С++. В С++ он указывает на динамическое распределение, тогда как в С# он используется для любой конструкции.]
Во-вторых, всякий раз, когда вы вызываете new
в С++, возвращаемое значение должно быть передано непосредственно в умный указатель. Умный указатель гарантирует, что delete
автоматически вызывается для вас в соответствующее время.
Кстати, если вы не гуру, который пишет низкоуровневую библиотеку (или учащийся, изучающий, как это сделать), вы никогда не должны вызывать new
для распределения массива на С++. Стандартная библиотека (а также Boost/TR1) предоставляет классы шаблонов, которые выделяют и управляют массивами для вас.
Таким образом, С++ не использует сборщик мусора, но у него есть своя форма автоматического управления памятью. Существуют тонкие различия между двумя подходами, но оба подхода автоматизируют выпуск памяти, тем самым устраняя большинство типов утечек памяти.
Авторитетная демонстрация этих понятий дана создателем С++ Бьярном Страуступом в ответ на вопрос: Как я могу справиться с утечками памяти?
См. также:
- Справочник по управлению динамической памятью - интеллектуальные указатели
- Ссылка на библиотеку контейнеров - массивы
Ответ 4
Вы можете использовать С++ с .NET двумя способами: управляемыми или неуправляемыми. В управляемом режиме сборка мусора .NET позаботится об освобождении памяти от вашего имени; в неуправляемом режиме вы близки к нормальному/стандартному поведению С++, поэтому вам нужно самому взять на себя ответственность за себя.
Ответ 5
Да, вы правы, в стандартном С++ (в управляемом С++ или других вариантах это зависит) вы должны использовать delete после каждого нового. В С#, Java и других сборках, связанных с мусором, это необязательно (фактически большинство из них не имеют эквивалента оператору delete).
Ответ 6
"в С++ нет сборки мусора."
Правильно.
Ответ 7
Автоматическая сборка мусора полезна, но вы все равно можете получить утечки памяти, как показывает этот вопрос:
Он уменьшен в .NET и Java, но это не значит, что он автоматически обрабатывает плохое кодирование.
Итак, в С++ вам нужно явно освободить то, что вы запрашиваете, и я думаю, что это иногда лучше, поскольку вы знаете, что происходит. Я хочу, чтобы в .NET и Java сборщик мусора мало работал в режиме отладки, чтобы помочь людям понять, что они делают.
Ответ 8
Исправьте, вам нужно беспокоиться о сборке мусора на С++.
И... есть не нужно беспокоиться о сборке мусора на .NET.
Только если у вас есть такие интенсивные и длинные сценарии, которые вам нужны, вам нужно сосредоточиться на оптимизации.
Редактировать: Оба асвекау и Павел Минаев замечательно, спасибо! Я передал сообщение об ошибке.