2010-02-22 11 views
6

Supongamos que tengo una clase llamada R:¿Cuál es la diferencia entre estos dos enfoques de instanciación de objetos?

Class A 
{ 
... 
} 

Y lo que es la diferencia entre los 2 siguientes enfoques para instanciar un objeto:

void main(void) 
{ 
    A a; // 1 
    A *pa=new A(); // 2 
} 

Como mi comprensión actual (no estoy seguro sobre esto todavía):

  • Enfoque 1 asignar el objeto a en el marco de pila del método main(), y por lo que este objeto no se puede eliminar porque que deleti no tiene sentido (aún no sé por qué, ¿alguien podría explicar eso?).

  • Enfoque 2 asignar el objeto a en el montón del proceso y también un A * vairable pa en el marco de pila del método main(), por lo que el objeto puede ser suprimido y y la AP puede asignar nulo después de la eliminación.

Am I right? Si mi comprensión es correcta, ¿podría alguien decirme por qué no puedo eliminar el objeto a de la pila en el planteamiento 1?

Muchas gracias ...

+4

Por favor, cambie 'void main (void)' a 'int main()'. – avakar

+0

Sí. En general, no desea escribir la función (nulo) {}. Muchas autoridades lo consideran mala sintaxis: http://www.parashift.com/c++faq-lite/newbie.html#faq-29.4 –

Respuesta

1

Enfoque 1 declaran una variable y crea un objeto. En el Método 2, creó una instancia y un puntero a ella.

EDIT: En la aproximación 1, el objeto saldrá del alcance y se eliminará automáticamente. En el enfoque 2, el puntero se eliminará automáticamente, pero no a lo que apunta. Ese será tu trabajo.

+0

Err, no, se llama al constructor predeterminado. – gregseth

+1

hola, fastcodejava, gracias por su respuesta. esto es sintaxis C++, no C#. El enfoque 1 crea una instancia de objeto. Porque puedo acceder a sus variables de memeber. – smwikipedia

+0

@smwikipedia - Estoy de acuerdo, escribí demasiado rápido. Corregí la respuesta. – fastcodejava

6

Objeto a tiene automático duración de almacenamiento por lo que se eliminará automáticamente al final del ámbito en el que está definido. No tiene sentido intentar eliminarlo manualmente. La eliminación manual solo se requiere para objetos con duración de almacenamiento dinámico como *pa que se ha asignado usando new.

0

La memoria de la pila no se gestiona de la misma manera que la memoria del montón. no tiene sentido eliminar objetos de la pila: se eliminarán automáticamente al finalizar el alcance/función .

4
  1. Los objetos viven el tiempo es limitado a el alcance de la variable se define en , una vez que salga del alcance del objeto será limpiado. En C++, un alcance está definido por cualquier Bloque entre {an el correspondiente}.
  2. Aquí solo el puntero está en la pila y no en el objeto, por lo que cuando abandone el osciloscopio solo se borrará el puntero , el objeto aún estará en algún lado.

Para borrar un objeto, eliminar no solo llama al destructor de su objeto sino también liberar su memoria, esto no funcionaría ya que el compilador automatiza la administración de la pila, en contraste con el montón no está automatizado y requiere llamadas a nuevo y eliminar para administrar el tiempo en vivo de un objeto.
Cualquier objeto creado por una llamada a un nuevo debe ser eliminado una vez, olvidando hacer esto da como resultado una pérdida de memoria ya que la memoria de los objetos nunca será liberada.

1

Asignación hace dos cosas:
1) Asigna memoria para el objeto
2) llama al constructor de la memoria asignada

Supresión hace dos cosas:
1) llama al destructor del objeto
2) Desasigna la memoria utilizada por el objeto destruido

Cuando asigna en la pila (A a;), le está diciendo al compilador "por favor, haga un objeto para mí, asignando memoria, luego llame al t él constructor en esa memoria. Y mientras lo hace, ¿podría manejar llamar al destructor y liberar la memoria, cuando se sale del alcance? ¡Gracias! ". Una vez que la función (principal) finaliza, el objeto sale del ámbito, se llama al destructor y se libera la memoria.

Cuando asigna en el montón (A* pa = new A();), le está diciendo al compilador "Por favor, haz un objeto para mí". Sé lo que estoy haciendo, así que no te molestes en llamar al destructor o en liberar la memoria. Te diré cuándo hacerlo, en otro momento ". Una vez que la función (principal) finaliza, el objeto que asignaste permanece dentro del alcance, y no se destruye o libera. Afortunadamente, tienes un puntero almacenado en otro lugar de tu programa (como en, copió pa en alguna otra variable con un alcance mayor). Tendrá que decirle al compilador que destruya el objeto y libere la memoria en algún momento en el futuro. De lo contrario, obtendrá una pérdida de memoria.

En pocas palabras, el comando "eliminar" es solo para objetos asignados en el montón, porque esa es la interfaz de administración de memoria manual en C++ - nuevo/eliminar. Es un comando para el asignador de montón, y el asignador de montón no Saber algo acerca de los objetos asignados a la pila. Si intentas llamar a eliminar en un objeto asignado a la pila, también podrías haberlo llamado en una dirección de memoria aleatoria: son lo mismo en la medida en que el asignador de heap es contra. Cerned Muy parecido al intentar acceder a un objeto fuera de límites de la matriz:

int a[10]; 
std::cout << a[37] << "\n"; // a[37] points at... ? no one knows! 

Simplemente no tiene la intención de hacer eso :)

Editar: P. S. Las pérdidas de memoria son más importantes cuando asigna memoria en una función que no sea main. Cuando el programa finaliza, la memoria filtrada se desasigna, por lo que una pérdida de memoria en main puede no ser un gran problema, dependiendo de su escenario. Sin embargo, los destructores nunca reciben un llamado a los objetos filtrados. Si el destructor hace algo importante, como cerrar una base de datos o un archivo, entonces es posible que tenga un error más grave en sus manos.

+0

Técnicamente, el objeto no existe antes de la finalización del constructor. El constructor crea un objeto fuera de la memoria bruta. Si el constructor lanza una excepción, nunca hubo un objeto. – fredoverflow

+0

Sí, eso es correcto. Voy a enmendar mi respuesta –

1

Imagine stack como void* stack = malloc(1.000.000);
Ahora, este bloque de memoria es administrado internamente por el compilador y la CPU.
Es una pieza compartida de memoria. Cada función puede usarlo para almacenar objetos temporales allí.

Eso se llama almacenamiento automático.No puede borrar partes de esa memoria porque su propósito es
para volver a utilizar. Si elimina memoria explícitamente, esa memoria vuelve al sistema,
y no desea que eso suceda en una memoria compartida.

En cierto modo, los objetos automáticos también se obtienen borrados. Cuando un objeto se sale del alcance, el compilador coloca
una llamada invisible al destructor del objeto y la memoria vuelve a estar disponible.

+0

Gracias Nick. Por lo tanto, la pila está "planificada" en tiempo de compilación y permanece ocupada por el programa a lo largo de su vida útil, mientras que la pila se puede solicitar y liberar en tiempo de ejecución. Si es así, ¿qué pasa si el tamaño de la pila no es lo suficientemente grande? ¿podría ajustarse su tamaño en tiempo de ejecución? – smwikipedia

+0

@smwikipedia, de hecho, más el código se ejecuta en * thread *. Por lo general, cada hilo tiene su propia pila. Si creas explícitamente un hilo, puedes configurar su tamaño de pila. En Windows, vea, por ejemplo, http://msdn.microsoft.com/en-us/library/ms682453%28VS.85%29.aspx –

+0

... también los compiladores tienen la opción de establecer el tamaño de pila predeterminado de la aplicación. Como la pila tiene un tamaño fijo, puede ocurrir un desbordamiento de la pila: http://en.wikipedia.org/wiki/Stack_overflow –

1

No puede eliminar objetos en la pila porque está implementado en la memoria exactamente de esa manera, como una pila. A medida que crea objetos en la pila, se agregan uno encima del otro. A medida que los objetos abandonan el alcance, se destruyen desde la parte superior, en el orden opuesto en el que se crearon (se agregan a la parte superior de la pila y se eliminan de la parte superior de la pila). Intentar llamar al delete en algo de la pila podría romper ese orden. La analogía sería como tratar de sacar algo de papel de una pila de papeles.

El compilador controla cómo se crean y eliminan los objetos en la pila. Puede hacerlo porque sabe exactamente qué tan grande es cada objeto en la pila. Dado que el tamaño de la pila se establece en tiempo de compilación, significa que la asignación de memoria para las cosas en la pila es extremadamente rápida, mucho más rápida que la asignación de memoria del montón, que es controlado por el sistema operativo.

Cuestiones relacionadas