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?
}
È stato utile?

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,

  1. Nel primo caso, dal momento che si rigenerare con throw; (che, a differenza throw err;, conserva l'oggetto eccezione originale, con le modifiche, in detto "luogo magico" a 0x98e7058) riflettere la chiamata a append ()
  2. Nel secondo caso, dal momento che gettare qualcosa in modo esplicito, un copiare di err verrà creato poi gettato di nuovo (in un diverso 0x98e70b0 "luogo magico" - perché per tutto il compilatore sa err potrebbe essere un oggetto in pila sul punto di essere unwinded, come e era a 0xbfbce430, non nel "luogo magico" a 0x98e7058), 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top