C ++ Eccezioni domande sul rethrow di eccezione originale
Domanda
Sarà il seguente append () nella cattura causa l'eccezione rilanciati per vedere l'effetto di append () essere chiamato?
try {
mayThrowMyErr();
} catch (myErr &err) {
err.append("Add to my message here");
throw; // Does the rethrow exception reflect the call to append()?
}
Allo stesso modo, se riscrivo in questo modo, si verificano volontà po affettare se l'eccezione reale è derivato da myerr?
try {
mayThrowObjectDerivedFromMyErr();
} catch (myErr &err) {
err.append("Add to my message's base class here");
throw err; // Do I lose the derived class exception and only get myErr?
}
Soluzione
In entrambi i casi, dal momento che si cattura con riferimento, si sta effettivamente alterare lo stato dell'oggetto eccezione originale (che si può pensare, come residente in una posizione di memoria magica che rimarrà valida durante il successivo svolgimento - 0x98e7058
nell'esempio qui sotto). Tuttavia,
- Nel primo caso, dal momento che si rigenerare con
throw;
(che, a differenzathrow err;
, conserva l'oggetto eccezione originale, con le modifiche, in detto "luogo magico" a0x98e7058
) riflettere la chiamata a append () - Nel secondo caso, dal momento che gettare qualcosa in modo esplicito, un copiare di
err
verrà creato poi gettato di nuovo (in un diverso0x98e70b0
"luogo magico" - perché per tutto il compilatore saerr
potrebbe essere un oggetto in pila sul punto di essere unwinded, comee
era a0xbfbce430
, non nel "luogo magico" a0x98e7058
), in modo da si perde specifici della classe derivata dati durante la copia-costruzione di un'istanza di classe di base.
Semplice programma per illustrare ciò che sta accadendo:
#include <stdio.h>
struct MyErr {
MyErr() {
printf(" Base default constructor, this=%p\n", this);
}
MyErr(const MyErr& other) {
printf(" Base copy-constructor, this=%p from that=%p\n", this, &other);
}
virtual ~MyErr() {
printf(" Base destructor, this=%p\n", this);
}
};
struct MyErrDerived : public MyErr {
MyErrDerived() {
printf(" Derived default constructor, this=%p\n", this);
}
MyErrDerived(const MyErrDerived& other) {
printf(" Derived copy-constructor, this=%p from that=%p\n", this, &other);
}
virtual ~MyErrDerived() {
printf(" Derived destructor, this=%p\n", this);
}
};
int main() {
try {
try {
MyErrDerived e;
throw e;
} catch (MyErr& err) {
printf("A Inner catch, &err=%p\n", &err);
throw;
}
} catch (MyErr& err) {
printf("A Outer catch, &err=%p\n", &err);
}
printf("---\n");
try {
try {
MyErrDerived e;
throw e;
} catch (MyErr& err) {
printf("B Inner catch, &err=%p\n", &err);
throw err;
}
} catch (MyErr& err) {
printf("B Outer catch, &err=%p\n", &err);
}
return 0;
}
Risultato:
Base default constructor, this=0xbfbce430
Derived default constructor, this=0xbfbce430
Base default constructor, this=0x98e7058
Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
Derived destructor, this=0xbfbce430
Base destructor, this=0xbfbce430
A Inner catch, &err=0x98e7058
A Outer catch, &err=0x98e7058
Derived destructor, this=0x98e7058
Base destructor, this=0x98e7058
---
Base default constructor, this=0xbfbce430
Derived default constructor, this=0xbfbce430
Base default constructor, this=0x98e7058
Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
Derived destructor, this=0xbfbce430
Base destructor, this=0xbfbce430
B Inner catch, &err=0x98e7058
Base copy-constructor, this=0x98e70b0 from that=0x98e7058
Derived destructor, this=0x98e7058
Base destructor, this=0x98e7058
B Outer catch, &err=0x98e70b0
Base destructor, this=0x98e70b0
Si veda anche:
Altri suggerimenti
Questa domanda è piuttosto vecchio e ha un'adeguata risposta al momento in cui è stato chiesto. Tuttavia, voglio solo aggiungere una nota su come fare una corretta gestione delle eccezioni in quanto C ++ 11 e credo che questo corrisponde molto bene a quello che stavi cercando di raggiungere con la funzione di accodamento:
std::nested_exception
e std::throw_with_nested
E 'descritto su StackOverflow qui e qui , come è possibile ottenere un backtrace sulle eccezioni all'interno del vostro codice senza bisogno di un debugger o ingombrante registrazione, semplicemente scrivendo un gestore di eccezioni corretta che rigenerare eccezioni nidificate .
Dato che è possibile farlo con qualsiasi classe di eccezione derivata, è possibile aggiungere un sacco di informazioni a tale backtrace! Si può anche dare un'occhiata al mio MWE su GitHub , dove un backtrace sarebbe simile in questo modo:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Sì, rethrowing genera nuovamente l'oggetto eccezione originale, che è stata modificata da un riferimento. È anche possibile prendere un riferimento classe base, modificare da esso ed essere ancora in grado di rigenerare il tipo di eccezione originale derivato dal throw;
.
per la prima domanda, sì.
, ma per il secondo, fare riferimento a Vlad risposta. è necessario progettare con attenzione il vostro oggetto eccezione per maniglia copia ctor. per convenzione, classe di base non riconosce il suo bambino così è molto probabile perdere i dati aggiuntivi trasportati da classe derivata.