Tengo un objeto C++ simple que creo al comienzo de la función F() para asegurar que se invocan dos funciones coincidentes (OpDo, OpUndo) al inicio y el retorno de la F() , utilizando el constructor y el destructor del objeto. Sin embargo, no quiero que la operación se deshaga en caso de que se haya lanzado una excepción dentro del cuerpo de F(). ¿Es esto posible hacerlo limpiamente? He leído sobre std :: uncaught-exception, pero su uso no parece ser recomendable.Cómo detectar el desenrollado de la pila en un Destructor
Respuesta
La mayoría de las personas han usado std::uncaught_exception()
para tratar de saber si hay una excepción pendiente, por lo que pueden lanzar una excepción desde un destructor si no hay uno ya. Eso generalmente se considera No una Buena Idea.
Si no desea deshacer una operación si se ha lanzado una excepción, debería funcionar.
Recuerde que el destructor es su última oportunidad de liberar los recursos que tiene un objeto, porque una vez que el destructor finaliza, el objeto no existe y todos los recursos que posee se filtran de forma permanente. Si OpDo()
asigna cualquier memoria o manejadores de archivos o lo que sea, debe tratar eso en el destructor pase lo que pase.
Vamos a suponer que su F vuelve alguna clase auxiliar:
Helper F()
{
MyClass doUndoWrapper;
}
Cuando el flujo es normal - se crea ayudante. Cuando se produce una excepción, no se crea una copia de Helper. Intenta usar esta semántica al ubicar al constructor de la región privada de Helper y declarar a F como amigo, para que nadie pueda crear ayuda.
class Helper
{
private:
friend Helper F();
Helper(){ //place there OpDo semantic - first entry
// construct this class
Helper(const Helper& copy){ //this must present to allow stack operations
// copy constructor will be called at end of `F` to return value
// so place OpUndo semantic there to mark success without exception
¿Qué? Esa no es una respuesta muy clara en absoluto. –
@C Johnson - Si usa 'Helper' como valor de retorno obtiene los beneficios follow (1) Helper se crea al principio según se requiera (así que coloque OpDo en el constructor) (2) Puede reconocer si la función F ha regresado exitosamente - el constructor de copia llamado (así que coloque OpUndo allí) (3) en caso de excepción no se llama a ningún constructor de copia. Para aclarar esto, estoy cambiando el código para reflejar esta idea. – Dewfy
Puede subvertir el Scope Guard idiom. En lugar de no hacer algo en el destructor cuando se produce ninguna excepción, invertimos eso y única hacer algo si se lanza una excepción:
class DoUndoRAII{
public:
DoUndoRAII()
: noexcept_(false)
{
// your stuff here
}
~DoUndoRAII(){
if(noexcept_){
// do whatever you need to do
}
}
void no_exception(){
noexcept_ = true;
}
private:
bool noexcept_;
};
void func(){
DoUndoRAII do_undo;
// last line
do_undo.no_exception();
}
Cuando se produce una excepción, do_undo.no_exception()
nunca serán llamados y por lo tanto, nunca establezca el valor noexcept_
en verdadero. :) Se puede encontrar un ejemplo here on Ideone.
- 1. ¿Qué es el desenrollado de la pila?
- 2. Desenrollado de pila en HP-UX y Linux
- 3. ¿Cómo implementa gcc el desenrollado de la pila para las excepciones de C++ en Linux?
- 4. Java y C++ en problema de desenrollado de pila
- 5. Comportamiento diferente Pila de desenrollado en x64 y x32
- 6. ¿Detecta cuándo se ejecuta el destructor debido a una excepción?
- 7. Cómo detectar el valor de registros en un marco de pila de llamadas específico en windbg
- 8. Cómo sobrecargar un destructor?
- 9. ¿Cuándo es efectivo el desenrollado de lazo?
- 10. devolver la variable de pila de C++
- 11. Destructor privado
- 12. Cómo obtener el seguimiento de la pila de un hilo
- 13. Escribiendo un destructor LinkedList?
- 14. Objeto asignado a la pila de C++, llamada al destructor explícito
- 15. Creación de objetos en la pila/pila?
- 16. argumentos de plantilla dentro de un tiempo de compilación desenrollado para el bucle?
- 17. ¿Cómo prevenir un desbordamiento de pila al monitorear el tamaño de la pila?
- 18. Cómo detectar la redirección en un UIWebView
- 19. Uso de "esto" en el destructor
- 20. ¿Qué sucede con el destructor de la clase base si un destructor de clase derivado lanza una excepción?
- 21. ¿Cómo escribir un destructor de clase en Scala?
- 22. Cómo obtener la pila de pila nativa de las excepciones nativas capturadas en el código administrado
- 23. Establezca el tamaño de la pila con setrlimit() y provoque un desbordamiento de la pila/segfault
- 24. ¿Cómo puedo aumentar el tamaño de la pila en Python?
- 25. ¿Cómo detectar el final de la secuencia?
- 26. ¿Cómo imprimir el seguimiento completo de pila en la excepción?
- 27. Cómo obtener la pila completa de StackOverflowError
- 28. ¿Cómo rebosar la pila sin empujar nuevos marcos de pila?
- 29. Debe proporcionar destructor en el PIMPL
- 30. Aparentemente estoy corrompiendo la pila, pero ¿cómo?
Usar'uncaught_exception' podría estar bien, pero depende de lo que esté haciendo (y por lo tanto es subjetivo ...). Sin embargo, ¿podría explicar un poco más sobre la operación do/undo y la (s) excepción (es)? – Macke
Si no desea que suceda una acción cuando se propone una excepción, simplemente no use RAII. Simplemente coloque el OpDo() y OpUndo() directamente en el código. –
"su uso no parece ser recomendado", porque no funciona como un medio para detectar si el bit de pila que contiene su objeto se está desenrollando debido a una excepción o debido a un retorno normal. Supongamos que alguien pone un código en un destructor que llama a su función F. Supongamos además que dicho objeto se destruye como parte del desenrollado de la pila durante una excepción. Entonces 'uncaught_exception' devolverá' true', pero no se ha lanzado ninguna excepción dentro del cuerpo de F(). –