Question

Est-ce que d'être appelé l'append suivante () dans la prise provoquer l'exception relancée pour voir l'effet de append ()?

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 réécris cette façon, va trancher peu se produire 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?
}
Était-ce utile?

La solution

Dans les deux cas, puisque vous attrapez par référence, vous modifiez efficacement l'état de l'objet d'exception originale (que vous pouvez penser comme résidant dans 0x98e7058) refléter l'appel à append ()

  • Dans le second cas, puisque vous jetez quelque chose explicitement, Copier de err sera créé puis jeté à nouveau (à un autre « lieu magique » 0x98e70b0 - parce que pour tout le compilateur sait err pourrait être un objet sur la pile sur le point d'être unwinded, comme e était 0xbfbce430, pas dans le « lieu magique » à 0x98e7058), donc vous perdrez des données spécifiques à chaque classe dérivées au cours de la construction de 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
    

    Voir aussi:

    Autres conseils

    Cette question est assez ancienne et a une réponse appropriée au moment où il a été demandé. Cependant, je veux juste ajouter une note sur la façon de faire la gestion des exceptions appropriée depuis C 11 ++ et je crois que cela correspond très bien à ce que vous essayez d'atteindre avec votre fonction append:

    std::nested_exception et std::throw_with_nested

    Il est décrit sur StackOverflow et ici , comment vous pouvez obtenir une trace sur vos exceptions dans votre code sans besoin d'un débogueur ou l'exploitation forestière lourde, en écrivant simplement un gestionnaire d'exception appropriée qui réémettre exceptions imbriquées .

    Comme vous pouvez le faire avec une classe d'exception dérivée, vous pouvez ajouter beaucoup d'informations à un tel backtrace! Vous pouvez également jeter un oeil à mon MWE sur GitHub, où un backtrace 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, rethrowing rethrows l'objet d'exception d'origine, que vous avez modifié par une référence. Vous pouvez également prendre une référence de classe de base, modifier par et être encore capable de réémettre le type d'exception dérivée originale par throw;.

    pour la première question, oui.

    mais pour la deuxième, se référer à la réponse Vlad. vous aurez besoin de concevoir soigneusement votre objet d'exception pour gérer copie cteur. par convention, classe de base ne reconnaît pas son enfant si vous perdrez très probablement les données supplémentaires effectuées par classe dérivée.

    Licencié sous: CC-BY-SA avec attribution
    Non affilié à StackOverflow
    scroll top