Pergunta

O seguinte Append () na captura fará com que a exceção do Rethrown veja o efeito de ser chamado Append ()?

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

Da mesma forma, se eu reescrevê -lo dessa maneira, o fatiamento ocorrerá se a exceção real for derivada 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?
}
Foi útil?

Solução

Nos dois casos, como você pega por referência, você está efetivamente alterando o estado do objeto de exceção original (que você pode pensar como residindo um local de memória mágica que permanecerá válida durante o desenrolar subsequente -- 0x98e7058 no exemplo abaixo). No entanto,

  1. No primeiro caso, desde que você repensa com throw; (que, diferentemente throw err;, preserva o objeto de exceção original, com suas modificações, na referida "localização mágica" em 0x98e7058) vai refletir a chamada para anexar ()
  2. No segundo caso, como você joga algo explicitamente, um cópia de do err será criado então jogado novamente (em um "local mágico" diferente 0x98e70b0 - porque para todo o compilador sabe err poderia ser um objeto na pilha prestes a ser não suoso, como e estava em 0xbfbce430, não na "localização mágica" em 0x98e7058), assim você perderá dados específicos da classe derivada Durante a construção de cópias de uma instância da classe base.

Programa simples para ilustrar o que está acontecendo:

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

Resultado:

  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

Veja também:

Outras dicas

Esta pergunta é bastante antiga e tem uma resposta apropriada ao tempo que foi feita. No entanto, eu só quero adicionar uma nota sobre como fazer o manuseio de exceção adequado, pois C ++ 11 E acredito que isso corresponde muito bem ao que você estava tentando alcançar com sua função de anexo:

Usar std::nested_exception e std::throw_with_nested

É descrito no StackOverflow aqui e aqui, Como voce pode Obtenha uma volta nas suas exceções Dentro do seu código, sem a necessidade de um depurador ou um registro complicado, simplesmente escrevendo um manipulador de exceção adequado que retornará as exceções aninhadas.

Como você pode fazer isso com qualquer classe de exceção derivada, você pode adicionar muitas informações a esse backtrace! Você também pode dar uma olhada no meu Mwe no github, onde um backtrace seria algo assim:

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"

Sim, o Rethrowing RethRows o objeto de exceção original, que você modificou por uma referência. Você também pode capturar uma referência de classe base, modificar por ela e ainda ser capaz de repetir o tipo de exceção derivada original por throw;.

Para primeira pergunta, sim.

Mas, por segundo, consulte a resposta do VLAD. Você precisará projetar cuidadosamente seu objeto de exceção para lidar com cópia. Por convenção, a classe base não reconhece seu filho, então você provavelmente perderá os dados adicionais transportados por classe derivada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top