Обнаружение активных исключений в деструкторе - PullRequest
8 голосов
/ 01 апреля 2011

У меня есть класс, который использует RAII для очистки на случай, если что-то пойдет не так.Это означает, что класс содержит флаг, который сообщает ему, была ли работа завершена, и если этот флаг не установлен, когда вызывается конструктор, он выполняет свои задачи по очистке и выдает сообщения журнала.Теперь я хотел бы, чтобы этот класс стал на один шаг более умным, то есть он должен выяснить, произошла ли ошибка, потому что работа была прервана (т.е. было сгенерировано исключение и вызван деструктор) или потому, что кто-то не использовал этот класс и никогдана самом деле закончил работу.Это означает, что мне придется выяснить в деструкторе, если исключение активно.Если он найден, я создаю сообщение журнала, возможно, распечатывая содержимое исключения, а затем перебрасывая его.Я предполагаю что-то вроде этого.

Foo::~Foo () {
  try { /* do not know what to put here */ }
  catch( const std::exception & ex ) {
     // produce error in log
     throw;
  }
  catch( ... ) {
    // produce some other log message
    throw;
   }
}

Однако я не уверен, сработает ли это вообще, поскольку исключение активно еще до вызова деструктора и не происходит из блока try.Также я использую throw; внутри деструктора, и на этом этапе я получаю исключение - это действительно плохая идея.Так что я бы не стал этого делать, если только стандарт четко не гарантирует, что этот случай является исключением (без каламбура) из этого правила (чего я не знаю).

Так возможно ли это вообще или должноЯ как-то справляюсь с этой ситуацией?

Ответы [ 3 ]

11 голосов
/ 01 апреля 2011

Вы можете использовать std::uncaught_exception(), который возвращает истину, если было сгенерировано исключение, но catch еще не обработало его. Вы можете использовать эту проверку в своем деструкторе, чтобы принимать решения о том, что он должен или не должен делать.

Предупреждение, хорошие руководящие принципы программирования обычно диктуют, что заставить ваш деструктор вести себя значительно по-разному при разных обстоятельствах, обычно не очень хорошая идея. Так что используйте эту функцию, но не злоупотребляйте ею. Обычно используется деструктор, который выбрасывает, только если нет активного необработанного исключения (эта функция возвращает false). Но этот тип поведения, как правило, не очень хороший дизайн. Если условие было достаточно плохим, чтобы оправдать исключение, его, вероятно, не следует игнорировать. И деструкторы не должны бросать исключения в любом случае.

Пример:

Foo::~Foo()
{
    if (std::uncaught_exception()) 
    {
        std::cerr << "Warning: Can't cleanup properly" << std::endl;
        return;
    }
    else
    {
        // ...
    }
}
2 голосов
/ 01 апреля 2011

Это невозможно сделать безопасным образом.

Что вы можете сделать, это проверить ваши параметры в деструкторе, и это должно сказать, была ли завершена обработка.

ByКстати, почему вы не регистрируете ошибку в блоке catch, где вы можете ее обработать?Там вы должны знать, что обработка была завершена с ошибкой.

1 голос
/ 01 апреля 2011

Посмотрите на этот мой вопрос и ответы .

По сути, вы можете сбросить активное в настоящий момент исключение, используя простой throw в первом блоке попытки. Однако это безопасно только в том случае, если вы точно знаете, что в настоящее время обрабатывается исключение, т. Е. Деструктор вызывается из блока catch. В противном случае throw вызовет std::terminate() ,

Foo::~Foo () {
  try {  throw; } // only if you *know* that an exception is active - bad thing for a generic destructor
  catch( const std::exception & ex ) {
     // produce error in log

  }
  catch( ... ) {
    // produce some other log message

   }
}

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

Шаблон обработки исключений - это хорошо, но я бы не стал делать это в несвязанном деструкторе. Снова, см. Упомянутый вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...