En primer lugar, recordar que los objetos en C++ pueden ser creado ya sea en la pila o en en el montón.
Un marco de pila (o ámbito) se define mediante una instrucción. Puede ser tan grande como una función o tan pequeño como un bloque de control de flujo (while
/if
/for
etc.). Un par arbitrario {}
que encierra un bloque arbitrario de código también constituye un marco de pila. Cualquier variable local definida dentro de un marco saldrá del alcance una vez que el programa salga del marco. Cuando una variable de pila sale del alcance, se llama a su destructor.
Así que aquí es un ejemplo clásico de un marco de pila (una ejecución de una función) y una variable local declarada en él, lo que va a pasar de alcance una vez que las salidas marco de pila - una vez que la función termina:
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.
Aquí se muestra un ejemplo en el que vemos un marco de pila de ser sólo el cuerpo de un comunicado if
:
if (myCondition) {
Circle c (20);
c.draw();
}
// c is now out of scope
// The destructor ~Circle() has been called
la única manera de que un objeto pila-creado para "permanecen en su alcance" después de la trama se sale es si es el valor de retorno de una función. Pero eso no es realmente "permanecer en el alcance" porque el objeto se está copiando. Entonces el original sale del alcance, pero se hace una copia. Ejemplo:
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.
Ahora, un objeto también se puede declarar en el montón. Por el bien de esta discusión, piense en el montón como una mancha de memoria amorfa. A diferencia de la pila, que asigna y desasigna automáticamente la memoria necesaria a medida que ingresa y sale de los fotogramas de pila, debe reservar manualmente y liberar la memoria de pila.
Un objeto declarado en el montón hace, de algún modo, "sobrevivir" entre los marcos de la pila. Se podría decir que un objeto declarado en el montón nunca sale del alcance, pero eso es realmente porque el objeto nunca está realmente asociado con ningún ámbito. Tal objeto se debe crear a través de la palabra clave new
, y se debe hacer referencia a él mediante un puntero.
Es su responsabilidad liberar el objeto Heap una vez que haya terminado con él. Libera objetos de montón con la palabra clave delete
. El destructor en un objeto de montón no se llama hasta que libere el objeto.
Los punteros que hacen referencia a los objetos del montón son generalmente variables locales asociadas con los ámbitos. Una vez que haya terminado de usar el objeto Heap, permitirá que el puntero (s) que hace referencia a él se salga del alcance. Si no ha liberado explícitamente el objeto al que apunta el puntero, entonces el bloque de la memoria del montón nunca se liberará hasta que el proceso finalice (esto se conoce como pérdida de memoria).
Piénselo de esta manera: un objeto creado en la pila es como un globo pegado a una silla en una habitación. Cuando salgas de la habitación, el globo se abrirá automáticamente. Un objeto creado en el montón es como un globo en una cinta, atado a una silla en una habitación. La cinta es el puntero. Cuando sale de la habitación, la cinta desaparece automáticamente, pero el globo simplemente flota hacia el techo y ocupa espacio. El procedimiento correcto es hacer estallar el globo con un alfiler, y luego salir de la habitación, con lo cual la cinta desaparecerá.Pero, lo bueno del globo en la cuerda es que también puedes desatar la cinta, sostenerla en tu mano, salir de la habitación y llevar el globo contigo.
Para ir a su lista vinculada ejemplo: normalmente, los nodos de dicha lista se declaran en el montón, con cada nodo sosteniendo un puntero al siguiente nodo. Todo esto está sentado en el montón y nunca sale de su alcance. Lo único que podría salir del alcance es el puntero que apunta a la raíz de la lista, el puntero que utiliza para hacer referencia a la lista en primer lugar. Eso puede ir fuera del alcance.
He aquí un ejemplo de cómo crear cosas en la pila, y el puntero raíz de salir del ámbito de aplicación:
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
Sus preguntas actualización es una muy buena, y la respuesta es, no. Cuando un puntero sale del alcance, el destructor del objeto al que apunta es ** ** llamado automáticamente. Tienes que llamarlo tú mismo, y esto sucede cuando llamas a 'delete' en el nodo para liberar la memoria. Esto es algo bueno a tener en cuenta cuando tiene una matriz o una lista de punteros a objetos con implementaciones de destructor significativas. Afortunadamente, ya que tienes que 'libre' estos tú mismo de todos modos, estarás activando los destructores. –
Por cierto, si realmente necesita una lista vinculada para algo, es mucho mejor usar std :: list que su propia lista vinculada personalizada. – DSimon
Debería haber dicho 'eliminar' en lugar de' libre'. Ignore 'free', es C legacy. Use solo 'new' y' delete' para la asignación/eliminación de heap. –