Во-первых, помните, что объекты в C++ может быть либо на стеке или на на куче.
Кадр стека (или область действия) определяется инструкцией. Это может быть такой же большой, как функция или малый, как блок управления потоком (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
. Деструктор объекта кучи не вызывается до тех пор, пока вы не освободите объект.
Указатели, относящиеся к объектам кучи, обычно являются локальными переменными, связанными с областями. Как только вы закончите использовать объект кучи, вы разрешаете указателю (указателям) ссылаться на него, чтобы выйти из области видимости. Если вы явно не освободили объект, на который указывает указатель, блок памяти кучи никогда не будет освобожден до тех пор, пока процесс не завершится (это называется утечкой памяти).
Подумайте об этом так: объект, созданный в стеке, подобен воздушному шару, прикрепленному к стулу в комнате. Когда вы выходите из комнаты, воздушный шар автоматически появляется. Объект, созданный на куче, похож на воздушный шар на ленте, привязанный к стулу в комнате. Лента - это указатель. Когда вы выходите из комнаты, лента автоматически исчезает, но воздушный шар просто плывет к потолку и занимает пространство. Правильная процедура состоит в том, чтобы вытащить воздушный шар с помощью штифта, а затем выйти из комнаты, после чего лента исчезнет.Но, хорошая вещь о воздушном шаре на струне, вы также можете развязать ленту, держать ее в руке и выйти из комнаты и взять с собой воздушный шар.
Итак, чтобы перейти к примеру связанного списка: обычно узлы такого списка объявляются в куче, причем каждый узел содержит указатель на следующий узел. Все это сидит на куче и никогда не выходит за рамки. Единственное, что может выйти из области видимости - указатель, указывающий на корень списка - указатель, который вы используете для ссылки в списке в первую очередь. Это может выйти из сферы действия.
Вот пример создания вещи в куче, а указатель корень выходит из области видимости:
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
Ваши вопросы обновления очень хороший, и ответ, нет. Когда указатель выходит из области видимости, деструктор объекта, на который он указывает, ** не ** автоматически вызывается. Вы должны называть это самостоятельно, и это происходит, когда вы вызываете 'delete' на узле, чтобы освободить память. Это хорошая вещь, о которой следует помнить, когда у вас есть массив или список указателей на объекты со значимыми реализациями деструктора. К счастью, поскольку вы все равно должны «освобождать» себя, вы будете запускать деструкторы. –
Кстати, если вам действительно нужен связанный список для чего-то, вам гораздо лучше использовать std :: list, чем собственный собственный связанный список. – DSimon
Я должен был сказать 'delete' вместо' free'. Игнорировать 'free', это C наследие. Используйте только 'new' и' delete' для размещения/удаления кучи. –