¿Cómo detectar el desenrollado de la pila en un destructor en C++?

¿Qué es el desenrollado de pilas?

El desenredado de pila es el proceso de ejecutar destructores en todos los objetos locales cuando una excepción se propaga desde una función. Ocurre cuando se lanza una excepción y no se detecta dentro de la misma función. Cuando esto sucede, los destructores para todos los objetos de duración de guardado automático declarados en esa función se llaman en el orden inverso de su declaración antes de que el control se pase a un controlador (si lo hay) o se devuelva a la persona que llama.

El desenrollado de la pila suele ser transparente para el programador y se realiza automáticamente. Stack Unwinding a menudo se asocia con el manejo de excepciones. Cuando se produce una excepción en C++, se busca linealmente en la pila de llamadas de función el controlador de excepciones y se eliminan todas las entradas anteriores a la función que contiene el controlador de excepciones. Si una excepción no se maneja en el mismo código, se requiere el manejo de la pila (donde se lanza). Desenredar la pila es esencialmente el proceso de llamar a los destructores para todos los objetos automatizados creados en tiempo de ejecución (cuando se lanza una excepción).

Diferentes formas de abordar Stack Unwinding:

Hay varias formas de abordar el tema del desenrollado de pilas en un destructor.

  • Una forma es mirarlo desde la perspectiva de lo que sucede cuando se lanza una excepción.
  • Otra forma es verlo desde la perspectiva de cómo se llama un destructor cuando un objeto se sale del alcance.

Si observamos cómo desenrollar la pila desde la perspectiva de que se lanza una excepción, podemos entender por qué es importante tener un destructor que pueda limpiarse solo.

Cuando se lanza una excepción:

La ejecución del programa salta al bloque catch más cercano. Pero antes de que eso suceda, se destruyen todos los objetos creados en el bloque try. Esto se aplica tanto a los objetos locales como a los objetos creados por la asignación de memoria dinámica. Si los destructores de estos objetos no se limpian correctamente, esto puede provocar pérdidas de memoria u otros problemas.

Desde la perspectiva de lo que se llama un destructor:

Puede ayudar a entender la importancia de un destructor. Se llama a un destructor cuando un objeto sale del alcance. Cuando un objeto sale del alcance, se llama al destructor y libera todos los recursos que estaba usando. Si el destructor no se limpia correctamente, puede provocar fugas de recursos u otros problemas.

¿Cómo detectar el asentamiento de la pila?

En un destructor, el desenrollado de la pila se puede detectar buscando signos de actividad de limpieza, como los siguientes:

  • Llamar a funciones que liberan recursos (por ejemplo, cerrar archivos o liberar memoria)
  • Registrar mensajes
  • Coloque banderas

Si se observa alguna de estas actividades en un destructor, es probable que se esté desenrollando la pila.

Usando std::uncaught_exception()

Puedes usar el std::excepción_no detectada() función que devuelve verdadero si se está manejando una excepción actualmente (es decir, lanzada pero aún no detectada). Entonces en tu destructor verificarías si std::excepción_no detectada() devuelve verdadero o falso y toma las medidas apropiadas en consecuencia.

Ejemplo:

C++

#include <bits/stdc++.h>

using namespace std;

 

class MyClass {

public:

    MyClass()

    {

        

    }

 

    ~MyClass() 

    {

        if (!std::uncaught_exception()) {

            

        }

                

    };

};

Anular la función std::terminate()

Para detectar cuándo se produce el asentamiento de la pila, puede utilizar el predeterminado::terminar() función. El tiempo de ejecución llama a esta función si no puede encontrar un controlador de excepciones adecuado. al superar predeterminado::terminar()puede establecer un punto de interrupción o registrar un mensaje para ayudar a depurar su programa.

Aquí hay un ejemplo de cómo anularía std::terminate():

C++

void my_terminate()

{

    

    std::cerr << "Stack unwinding detected!" << std::endl;

 

    

    std::terminate();

}

 

int main()

{

    

    std::set_terminate(my_terminate);

 

    try {

        

    }

    catch (...) {

        

    }

    return 0;

}

Al establecer una bandera en el constructor:

Coloque una bandera en el constructor y verifique esa bandera en el destructor. Si el indicador está establecido, sabrá que se llamó al destructor debido a una excepción. Aquí hay un ejemplo:

C++

class MyClass {

public:

    MyClass()

        : m_isUnwinding(false)

    {

        

    }

 

    ~MyClass()

    {

        if (m_isUnwinding) {

            

            

        }

        else {

            

        }

    };

};

Artículos relacionados:

Su Calificación Nos Ayuda a Mejorar