Ответ looong.
Automati c длительность хранения
Переменные "стека" (более точно известные как сущности с automati c длительность хранения) уничтожается, как только вы покидаете область, в которой они были объявлены. (То есть они «очищаются» и их память освобождается)
void my_function() {
node node1;
if (1 == 1) {
node node2;
node* node3_ptr = new node; // this node is *not* cleaned up automatically
} // node2 is destructed now
node node4;
} // node1 and node4 are destructed now
В приведенном выше коде node1
и node4
объявляются в разных частях внешней области видимости функции. Они будут «go прочь», когда функции завершатся.
Не имеет значения, выполняется ли функция до конца, рано ли возвращается, выдает исключение - если функция заканчивается, C ++ гарантирует, что они будут уничтожены. (Приложение, завершающее мертвую на своих треках, отличается.)
node2
объявлено внутри блока if
. Он будет уничтожен, когда код выйдет из блока if
- даже до завершения функции.
Это гарантированное автоматическое c уничтожение этих переменных в совершенно предсказуемое время - одна из самых сильных сторон C ++. Он называется «детерминированность c уничтожение» и является одной из причин, по которой C ++ является моим предпочтительным языком.
Dynami c длительность хранения
«Куча» переменных (то есть сущностей с «dynamici *»). 1087 * «место хранения» сложнее.
void my_leaky_function() {
node* node5;
new node;
node* node6 = new node;
}
node5
по-прежнему просто локальная переменная. Тот факт, что он имеет тип «указатель на узел», а не просто «узел», не имеет значения. Это переменная с автоматическим c продолжительностью, которая использует память. Его размер - это размер указателя (вероятно, 4 или 8 байт - зависит от вашей платформы), а не размер узла. Эта переменная «уходит», и ее память восстанавливается после завершения функции.
new node;
выделяет память в «свободном хранилище» (в разговорной речи называется «куча»). new
возвращает указатель на выделенную память, но этот код игнорирует указатель. Здесь не задействованы локальные переменные, и узел не уничтожается при завершении функции;
node* node6 = new node;
также выделяет достаточно места для объекта узла в свободном хранилище - но на этот раз указатель, возвращаемый new
, хранится в локальной переменной с именем node6
. NB: node6
является локальной переменной (которая хранит указатель, а не узел) и имеет автоматическую c продолжительность хранения. Переменная node6
исчезает (и несколько байтов используемой памяти освобождаются), когда функция завершается. НО узел, на который тоже указывал node6
- узел, который хранится в бесплатном хранилище - не уничтожен.
Когда эта функция заканчивается, она оставила два узла в бесплатном хранилище - и поскольку он отбросил указатели на каждый из них, никто не может удалить их. У него «утечка памяти».
Зачем использовать хранилище Dynami c?
C ++ обещает очищать автоматические значения c хранилища вашей функции всякий раз, когда вы покидаете их область действия. Обычно это то, что вы хотите.
Иногда функции необходимо создать значение, которое переживает вызов функции - значение, которое не должно быть уничтожено при выходе из функции.
Часто это значение может просто быть возвращенным вызывающей стороне (без new
, без указателей), и вызывающая сторона может делать с ней то, что они хотят. Часто значение хранится в некоторой коллекции, такой как вектор или массив, который уже выделил для него память. Но - в вашем примере вы хотите создать новый узел в связанном списке или дереве (или что-то в этом роде), и не имеет смысла уничтожать узел после завершения функции.
tl; dr;
То есть
- , если после окончания функции, которая его создает, должно существовать значение
- , и оно не просто возвращается вызывающей функции
- , и он не хранится в памяти какого-либо другого контейнера
, тогда свободный магазин - подходящее место для него.
Оооочень много go касается того, кто «владеет» значением и отвечает за его удаление - и использование умных указателей, а не сырых указателей - и исключений безопасности - и и и и и - но этот ответ уже больше, чем я хотел. Итак, позвольте мне закончить с этим:
Пока вы изучаете C ++, используйте указатели. Используйте бесплатный магазин. Сожги себя с утечками памяти и двойным удалением. Подумайте, как бы вы решили эти проблемы. Это дает вам хорошую основу для понимания абстракций, которые вы будете использовать позже.
Как только вы поймете указатели и динамическое хранилище c - как только вы поймете, как написать свой собственный связанный список или двоичное дерево с нуля - STOP ИСПОЛЬЗУЯ ИХ. В повседневном кодировании, если вы не являетесь экспертом в написании кода для библиотеки контейнеров, никогда не используйте new
или delete
снова - никогда. Используйте умные указатели, когда это абсолютно необходимо, но старайтесь избегать даже их.
Положитесь на автоматическую c длительность хранения, когда сможете. Deterministi c разрушение ваш друг. Это то, что отличает C ++ от C. Это то, что отличает C ++ от мусорных языков. Именно поэтому C ++ по-прежнему является одним из королей языков программирования.