113 votes

Questions sur les exceptions C++ concernant le rejet de l'exception originale

Le fait de suivre append() dans le catch fera-t-il en sorte que l'exception rejetée verra l'effet de l'appel 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 le réécris de cette façon, le découpage en 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?
}

147voto

vladr Points 34562

Dans les deux cas, puisque vous attrapez 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 le dossier un emplacement mémoire magique qui restera valide lors du déroulement ultérieur -- 0x98e7058 dans l'exemple ci-dessous). Cependant,

  1. Dans le premier cas, puisque vous relancez avec throw; (qui, contrairement à throw err; préserve l'objet d'exception original, avec vos modifications, dans ledit "emplacement magique" à 0x98e7058 ) sera reflète l'appel à append()
  2. Dans le second cas, puisque vous lancez quelque chose de manière explicite, un fichier copie de err sera créé puis relancé (à un autre "endroit magique"). 0x98e70b0 -- parce que pour autant que le compilateur sache err pourrait être un objet sur la pile sur le point d'être déroulé, comme e était à 0xbfbce430 et non dans le "lieu magique" à 0x98e7058 ), donc vous perdrez les données spécifiques aux classes dérivées lors de la copie-construction d'une instance de la 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 :

8voto

Tronic Points 6457

Oui, la relance relance l'objet d'exception original, que vous avez modifié par une référence. Vous pouvez également attraper une référence de classe de base, la modifier et toujours être en mesure de relancer le type d'exception dérivé original par throw; .

1voto

YeenFei Points 2100

Pour la première question, oui.

mais pour le second, référez-vous à la réponse de Vlad. vous devrez concevoir avec soin votre objet d'exception pour gérer le copy ctor. 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X