Est-ce que l'append () suivant dans le catch provoquera l'exception de rethrown pour voir l'effet d'append () appelé?
try {
mayThrowMyErr();
} catch (myErr &err) {
err.append("Add to my message here");
throw; // Does the rethrow exception reflect the call to append()?
}
De même, si je le réécris de cette façon, le découpage des bits se produira-t-il si l'exception réelle est dérivée par 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?
}
Dans les deux cas, puisque vous capturez par référence, vous modifiez effectivement l'état de l'objet d'exception d'origine (que vous pouvez considérer comme résidant dans n emplacement de mémoire magique qui restera valide pendant le déroulement suivant - - 0x98e7058
dans l'exemple ci-dessous). cependant,
throw;
(qui, contrairement à throw err;
, conserve l'objet d'exception d'origine, avec vos modifications, dans ledit "emplacement magique" à 0x98e7058
) va refléter l'appel à ajouter () err
sera créée puis relancée (à un autre "magique" emplacement" 0x98e70b0
- car pour tout le compilateur sait que err
pourrait être un objet sur la pile sur le point d'être déroulé, comme e
était à 0xbfbce430
, pas dans "l'emplacement magique" à 0x98e7058
), donc vous perdrez des données spécifiques à la classe dérivée pendant la construction de la copie d'une instance de classe de base.Programme simple pour illustrer ce qui se passe:
#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;
}
Résultat:
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
Regarde aussi:
Cette question est assez ancienne et a une réponse appropriée au moment où elle a été posée. Cependant, je veux juste ajouter une note sur la façon de gérer correctement les exceptions depuis C++ 11 et je pense que cela correspond très bien à ce que vous étiez essayer d'atteindre avec votre fonction d'ajout:
std::nested_exception
et std::throw_with_nested
Il est décrit sur StackOverflow ici et ici , comment vous pouvez obtenir une trace sur vos exceptions à l'intérieur de votre code sans avoir besoin d'un débogueur ou d'une journalisation encombrante, en écrivant simplement un gestionnaire d'exceptions approprié qui renverra les exceptions imbriquées.
Puisque vous pouvez le faire avec n'importe quelle classe d'exception dérivée, vous pouvez ajouter beaucoup d'informations à une telle trace! Vous pouvez également jeter un oeil à mon MWE sur GitHub , où une trace ressemblerait à quelque chose comme ceci:
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"
Oui, la relance renvoie à nouveau l'objet d'exception d'origine, que vous avez modifié par une référence. Vous pouvez également intercepter une référence de classe de base, la modifier et toujours pouvoir relancer le type d'exception dérivée d'origine par throw;
.
pour la première question, oui.
mais pour la seconde, référez-vous à la réponse de Vlad. vous devrez soigneusement concevoir votre objet d'exception pour gérer le ctor de copie. par convention, la classe de base ne reconnaît pas son enfant, vous perdrez donc très probablement les données supplémentaires portées par la classe dérivée.