Вопросы об исключениях C++ на переброске исходного исключения

Следующее добавит () в причине выгоды повторно брошенное исключение, чтобы видеть, что эффект добавляет () быть названным?

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

Точно так же, если я перепишу его этот путь, то разрядное разрезание произойдет, если фактическое исключение будет получено 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?
}
108
задан Gabe 2 March 2010 в 04:18
поделиться

3 ответа

В обоих случаях, поскольку вы перехватываете по ссылке, вы эффективно изменяете состояние исходного объекта исключения (который вы можете думать как находящийся в магической области памяти, которая останется действительной во время последующей раскрутки - 0x98e7058 в примере ниже).Однако,

  1. В первом случае, поскольку вы повторно выбрасываете с помощью throw; (который, в отличие от throw err; , сохраняет исходный объект исключения с вашими изменениями в указанном location "at 0x98e7058 ) будет отражать вызов append ()
  2. . Во втором случае, поскольку вы бросаете что-то явно, копия of err будет создан, а затем брошен заново (в другом «волшебном месте» 0x98e70b0 - потому что, насколько известно компилятору, err может быть объектом в стеке, который собирается быть развернутым, например, e был в 0xbfbce430 , а не в «волшебном месте» в 0x98e7058 ), поэтому вы потеряете зависящий от производного класса data во время создания копии экземпляра базового класса.

Простая программа для иллюстрации того, что происходит:

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

Результат:

  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

См. Также:

144
ответ дан 24 November 2019 в 03:32
поделиться

Да, повторное отбрасывание отбрасывает исходный объект исключения, который вы изменили ссылкой. Вы также можете поймать ссылку на базовый класс, модифицировать его и все равно иметь возможность перебросить исходный производный тип исключения с помощью throw;.

8
ответ дан 24 November 2019 в 03:32
поделиться

на первый вопрос, да.

, но во-вторых, обратитесь к ответу Влада. вам нужно будет тщательно спроектировать объект исключения для обработки ctor копирования. по соглашению базовый класс не распознает своего дочернего элемента, поэтому вы, скорее всего, потеряете дополнительные данные, переносимые производным классом.

1
ответ дан 24 November 2019 в 03:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: