Ответ 1
Во-первых, помните, что объекты в С++ могут быть созданы либо в стеке, либо в куче.
Кадр стека (или область) определяется оператором. Это может быть как большой, так и небольшой, как блок управления потоком (while
/if
/for
и т.д.). Произвольная пара {}
, содержащая произвольный блок кода, также представляет собой стек стека. Любая локальная переменная, определенная в кадре, выйдет за пределы области действия, как только программа выйдет из этого кадра. Когда переменная стека выходит из области видимости, ее деструктор вызывается.
Итак, вот классический пример фрейма стека (выполнение функции) и локальная переменная, объявленная внутри него, которая выйдет за пределы области после выхода из фрейма стека - после завершения функции:
void bigSideEffectGuy () {
BigHeavyObject b (200);
b.doSomeBigHeavyStuff();
}
bigSideEffectGuy();
// a BigHeavyObject called b was created during the call,
// and it went out of scope after the call finished.
// The destructor ~BigHeavyObject() was called when that happened.
Вот пример, где мы видим, что стек стека является только телом оператора if
:
if (myCondition) {
Circle c (20);
c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called
Единственный путь для объекта, созданного стеком, "оставаться в области видимости" после выхода фрейма, является возвратным значением функции. Но это действительно не "остается в области видимости", потому что объект копируется. Таким образом, оригинал выходит за рамки, но копия сделана. Пример:
Circle myFunc () {
Circle c (20);
return c;
}
// The original c went out of scope.
// But, the object was copied back to another
// scope (the previous stack frame) as a return value.
// No destructor was called.
Теперь объект также может быть объявлен в куче. Ради этой дискуссии подумайте о куче как о аморфном блоке памяти. В отличие от стека, который автоматически выделяет и деблокирует необходимую память при входе и выходе из фреймов стека, вы должны вручную зарезервировать и освободить память кучи.
Объект, объявленный в куче, после моды "выживает" между кадрами стека. Можно сказать, что объект, объявленный в куче, никогда не выходит за рамки, но это действительно потому, что объект никогда не ассоциируется с какой-либо областью. Такой объект должен быть создан с помощью ключевого слова new
и должен называться указателем.
Вы несете ответственность за освобождение объекта кучи, как только вы закончите с ним. Вы освобождаете объекты кучи с помощью ключевого слова delete
. Деструктор объекта кучи не вызывается до тех пор, пока вы не освободите объект.
Указатели, относящиеся к объектам кучи, обычно являются локальными переменными, связанными с областями. Как только вы закончите использовать объект кучи, вы разрешаете указателю (указателям) ссылаться на него, чтобы выйти из области видимости. Если вы явно не освободили объект, на который указывает указатель, блок памяти кучи никогда не будет освобожден до тех пор, пока процесс не завершится (это называется утечкой памяти).
Подумайте об этом так: объект, созданный в стеке, похож на воздушный шар, прикрепленный к стулу в комнате. Когда вы выходите из комнаты, воздушный шар автоматически появляется. Объект, созданный на куче, похож на воздушный шар на ленте, привязанный к стулу в комнате. Лента - это указатель. Когда вы выходите из комнаты, лента автоматически исчезает, но воздушный шар просто плывет к потолку и занимает пространство. Правильная процедура состоит в том, чтобы вытащить воздушный шар с помощью штифта, а затем выйти из комнаты, после чего лента исчезнет. Но, хорошая вещь о воздушном шаре на струне, вы также можете развязать ленту, держать ее в руке и выйти из комнаты и взять с собой воздушный шар.
Итак, перейдите к примеру связанного списка: обычно узлы такого списка объявляются в куче, причем каждый node содержит указатель на следующий node. Все это сидит на куче и никогда не выходит за рамки. Единственное, что может выйти из области видимости - указатель, указывающий на корень списка - указатель, который вы используете для ссылки в списке в первую очередь. Это может выйти из сферы действия.
Здесь приведен пример создания материала в куче и указатель root, выходящий из области видимости:
if (myCondition) {
Node* list_1 = new Node (3);
Node* list_2 = new Node (4);
Node* list_3 = new Node (5);
list_1->next = list_2;
list_2->next = list_3;
list_3->next = null;
}
// The list still exists
// However list_1 just went out of scope
// So the list is "marooned" as a memory leak