¿Cuándo un objeto está “fuera del scope”?

En C ++, ¿cuándo se define un objeto como “fuera de scope“?

Más específicamente, si tuviera una lista vinculada por separado, ¿qué definiría un objeto de nodo de lista individual como “fuera de scope”? O si un objeto existe y está siendo referenciado por una variable ‘ptr’, ¿es correcto decir que el objeto se define como “fuera del scope” en el momento en que se borra la referencia o apunta a un objeto diferente?

ACTUALIZACIÓN: Suponiendo que un objeto es una clase que tiene un destructor implementado. ¿Se llamará al destructor en el momento en que el objeto sale del scope?

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; } 

En otras palabras, si el Nodo es apuntado por list_1 llama a su destructor después de esta línea:

Nodo * list_1 = new Node (3);

?

Primero, recuerde que los objetos en C ++ se pueden crear en la stack o en el montón.

Un marco de stack (o scope) se define mediante una statement. 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 stack. Cualquier variable local definida dentro de un marco saldrá del scope una vez que el progtwig salga del marco. Cuando una variable de stack sale del scope, se llama a su destructor.

Entonces aquí hay un ejemplo clásico de un marco de stack (una ejecución de una función) y una variable local declarada dentro de él, que saldrá del scope una vez que el marco de stack salga, una vez que la función finalice:

 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í hay un ejemplo donde vemos un marco de stack que es solo el cuerpo de una statement if :

 if (myCondition) { Circle c (20); c.draw(); } // c is now out of scope // The destructor ~Circle() has been called 

La única forma de que un objeto creado por la stack “permanezca en el scope” después de salir del marco es si se trata del valor de retorno de una función. Pero eso no es realmente “permanecer en el scope” porque el objeto se está copiando. Entonces el original sale del scope, 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 stack, que asigna y desasigna automáticamente la memoria necesaria a medida que ingresa y sale de los fotogtwigs de stack, debe reservar manualmente y liberar la memoria de stack.

Un objeto declarado en el montón hace, de alguna manera, “sobrevivir” entre los marcos de la stack. Se podría decir que un objeto declarado en el montón nunca sale del scope, pero eso es realmente porque el objeto nunca está realmente asociado con ningún ámbito. Tal objeto debe crearse a través de la new palabra clave, 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 Heap 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 scope. 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 stack 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.

Por lo tanto, para ir a su ejemplo de la lista vinculada: 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 scope. Lo único que podría salir del scope 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 scope.

Aquí hay un ejemplo de cómo crear cosas en el montón, y el puntero de raíz sale del scope:

 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 
 { //scope is defined by the curly braces std::vector vec; } // vec is out of scope here! vec.push_back(15); 

“Fuera de scope” es una metonimia: como en, usar el nombre o la terminología de un concepto para hablar de algo estrechamente relacionado pero diferente.

En C ++, un scope es una región estática del texto del progtwig, por lo que algo “fuera de scope”, tomado literalmente, significa físicamente fuera de una región de texto. Por ejemplo, { int x; } int y; { int x; } int y; : la statement de y está fuera del scope en el que x es visible.

La metonimia “saliendo del scope” se usa para express la idea de que la activación / instanciación dinámica del entorno asociado con algún ámbito está finalizando. Y entonces las variables definidas en ese ámbito se van a ir (por lo tanto, “fuera del scope”).

Lo que realmente ha salido “fuera del scope” es el puntero de instrucción, por así decirlo; la evaluación del progtwig se está llevando a cabo en un ámbito que no tiene visibilidad para ese. ¡Pero no todo en un telescopio desaparece! Las variables estáticas seguirán allí la próxima vez que se ingrese el scope.

“Salir del scope” no es muy exacto, pero breve y todos entienden lo que significa.

Un objeto que se declara dentro de una función (o dentro de ciertas construcciones entre corchetes entre funciones) queda fuera del scope cuando la ejecución abandona esa parte del código.

 void some_func() { std::string x("Hello!"); // x is in scope here } // But as soon as some_func returns, x is out of scope 

Esto solo se aplica a las cosas declaradas en la stack, por lo que tiene poco que ver con las listas vinculadas individualmente, ya que los nodos de la lista generalmente se instanciarán en el montón con el new .

En este ejemplo, el puntero devuelto por new saldrá del scope cuando la función finalice, pero no pasará nada al Nodo mismo:

 void make_a_node() { Node* p = new Node; } // Oh noes a memory leak! 

Cuando sale del ámbito que fue declarado en 🙂

Su pregunta tal como está no es responsable sin ver la implementación. Todo se reduce a donde declaras este nodo.

 void Foo() { int i = 10; { int j = 20; } // j is out of scope } // i is out of scope