Pregunta

Supongamos que tengo una clase como esta:

#include <iostream>

using namespace std;

class Boda {
    private:
        char *ptr;

    public:
        Boda() {
            ptr = new char [20];
        }
        ~Boda() {
            cout << "calling ~Boda\n";

            delete [] ptr;
        }

        void ouch() {
            throw 99;
        }
};

void bad() {
    Boda b;
    b.ouch();
}

int main() {
    bad();
}

Parece que ~Boda destructor nunca se llama, por tanto, el recurso ptr nunca llegan liberado.

Aquí está la salida del programa:

terminate called after throwing an instance of 'int'
Aborted

Por lo que parece la respuesta a mi pregunta es No.

Pero pensé que la pila tiene desenrolla una excepción cuando echaron? ¿Por qué objeto no Boda b obtener destruido en mi ejemplo?

Por favor, ayúdame a entender este problema de recursos. Quiero escribir mejores programas en el futuro.

Además, es este el llamado RAII?

Gracias, Boda Cydo.

¿Fue útil?

Solución

Si la excepción no se detecta ninguna parte, entonces el tiempo de ejecución de C ++ es libre de ir directamente a la terminación del programa sin hacer ningún pila desenrollar o llamar a cualquier destructores.

Sin embargo, si se agrega un bloque try-catch alrededor de la llamada a bad(), verá el destructor del objeto Boda se llama:

int main() {
    try {
      bad();
    } catch(...) {  // Catch any exception, forcing stack unwinding always
      return -1;
    }
}

RAII medios que dinámicamente (montón) de memoria asignado siempre propiedad de una forma automática (pila) objeto asignado que desasigna cuando los destructs objeto. Esto se basa en la garantía de que el destructor será llamado cuando el objeto asignado automáticamente sale del ámbito, ya sea debido a un rendimiento normal o debido a una excepción.

Este comportamiento esquina de los casos no es normalmente un problema con respecto a RAII, ya que suele ser la razón principal por la que desea que los destructores de ejecución es para liberar memoria y toda la memoria es devuelto al sistema operativo cuando el programa termina de todos modos. Sin embargo, si sus destructores hacen algo más complicado, como tal vez eliminar un archivo de bloqueo en el disco o algo así, donde se haría una diferencia si el programa llamado destructores o no al estrellarse, es posible que desee para envolver su main en un bloque try-catch que las capturas de todo (sólo para salida a excepción de todos modos) sólo para asegurarse de que la pila siempre se desenrolla antes de terminar.

Otros consejos

El destructor no se ejecuta si se produce una excepción en el constructor.

se llevará a cabo si es necesario (en algún lugar si se maneja excepción) en caso de excepción se lanza en otro método como en su ejemplo. Pero a medida que se termina el programa, llamando al destructor no es necesario aquí y comportamiento depende del compilador ...

La idea de RAII es que asigna constructor Recursos y libera destructor ellos. Si se produce una excepción en el constructor, no existe una simple manera de saber Recursos wich donde atribuidas y que no eran (que depende del lugar exacto en el constructor, donde se produjo una excepción). También debe recordar que si falla un constructor, la única manera de decir a la persona que llama a lanzar una excepción y memoria asignada se libera (ya sea pila relajarse, o montón memoria asignada) como si nunca fuera asignado.

La solución es obvia: si alguna excepción puede ocurrir dentro de un constructor, que tiene que atraparla y liberar Recursos asignados si es necesario. De hecho, podría haber algún código duplicado con destructor, pero eso no es un gran problema.

En destructor que no debería plantear excepciones, ya que puede conducir a grandes problemas con la pila desenrollar.

En cualquier otro método, el uso de excepciones como desee, pero no se olvide de manejar en algún lugar. Un excception no controlada puede ser peor que no es una excepción en absoluto. Sé de algunos programas que no maneja excepciones para algunos errores menores ... y la caída de los errores que sólo debe emitir una advertencia.

Trate de lavado de la corriente - verá que el destructor se llama de hecho:

cout << "calling ~Boda" << endl;

Es el búfer de E / S que los retrasos de la impresión hasta el punto de que los recortes de terminación del programa de antes de la producción real.

Editar:

Lo anterior es válido para excepciones manejadas . Con las excepciones no controladas la norma no especifica si la pila se desenrolla o no. Ver también esta pregunta SO .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top