Pregunta

¿La siguiente adición () en la captura causa la excepción relanza para ver el efecto de la adición () se llama?

try {
  mayThrowMyErr();
} catch (myErr &err) {
  err.append("Add to my message here");
  throw; // Does the rethrow exception reflect the call to append()?
}

Del mismo modo, si vuelvo a escribir de esta manera, se produce poco rebanar voluntad si la excepción real se obtiene por 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?
}
¿Fue útil?

Solución

En ambos casos, ya que se captura por referencia, están alterando de manera efectiva el estado del objeto excepción original (que se puede considerar como residente en una ubicación de memoria mágico que permanecerá válido durante el desenrollamiento posterior - 0x98e7058 en el ejemplo a continuación). Sin embargo,

  1. En el primer caso, ya que volver a lanzar con throw; (que, a diferencia de throw err;, conserva el objeto de excepción original, con sus modificaciones, en dicho "lugar mágico" en 0x98e7058) reflejan la llamada a modo de adición ()
  2. En el segundo caso, ya que tirar algo de forma explícita, una copiar de err se creará entonces arrojado de nuevo (a una 0x98e70b0 "lugar mágico" diferente - porque para todo el compilador sabe err podría ser un objeto en la pila a punto de ser unwinded, como e estaba en 0xbfbce430, no en el "lugar mágico" en 0x98e7058), por lo que usted perderá la clase derivada datos específicos durante la copia de la construcción de una instancia de clase base.

programa simple para ilustrar lo que está sucediendo:

#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;
}

Resultados:

  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

También vea:

Otros consejos

Esta pregunta es bastante antiguo y tiene una respuesta apropiada a la vez que se le pidió. Sin embargo, sólo quiero añadir una nota sobre cómo hacer un manejo adecuado excepción, ya que C ++ 11 y creo que esto se corresponde muy bien a lo que estaba tratando de lograr con su función de agregación:

std::nested_exception y std::throw_with_nested

Se describe en StackOverflow aquí y aquí , cómo se puede conseguir una traza en sus excepciones dentro de su código sin necesidad de un depurador o engorroso de registro, simplemente escribiendo un manejador de excepción apropiado que volver a lanzar excepciones anidadas .

Ya que se puede hacer esto con cualquier clase de excepción derivada, se puede añadir una gran cantidad de información a la traza tales! También puede echar un vistazo a mi EPM en GitHub , donde un trazado inverso sería algo como esto:

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í, Regeneración de relanzamientos el objeto de excepción original, que ha modificado por una referencia. También se puede coger una referencia de la clase base, modificar por ella y aún así ser capaz de volver a lanzar el tipo de excepción derivada original de throw;.

para la primera pregunta, sí.

pero para la segunda, se refiere a la respuesta Vlad. tendrá que diseñar cuidadosamente su objeto de excepción a la copia de mango ctor. por convención, la clase base no reconoce su niño de modo que lo más probable es que pierda los datos adicionales realizadas por clase derivada.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top