Могу ли я по-прежнему выбрасывать исключение из функции, вызываемой внутри блока catch?

У меня есть следующая структура в устаревшей кодовой базе:

try{
...
}
catch(Type1&){
...
}
catch(Type2&){
...
}
...

А при разработке копирования-вставки одни и те же блоки захвата появляются везде.
Теперь я бы написал такую ​​функцию:

void catchErrors(){
try{
throw;
}
catch(Type1&){
...
}
...
}

и вставьте его в код, например так:

try{
...
}
catch(...){
catchErrors();
}

Будет ли это действительный рефакторинг, в результате чего такая же функциональность?
(И есть ли у вас лучшее предложение для рефакторинга?)

2

Решение

Да, это действительно.

[C++14: 15.1/8]: A вбрасывание выражение без операнда сбрасывает текущее обработанное исключение (15.3). Исключение повторно активируется с существующим объектом исключения; новый объект исключения не создается. Исключением не является
больше считается пойманным; следовательно, значение std::uncaught_exception() снова будет правдой.

[ Пример: код, который должен быть выполнен из-за исключения, но не может полностью обработать исключение, может быть написан так:

try {
// ...
} catch (...) { // catch all exceptions
// respond (partially) to exception
throw; // pass the exception to some
// other handler
}

— конец примера]

[C++14: 15.1/9]: Если в настоящее время не обрабатывается ни одно исключение, выполняется выражение throw без вызовов операндов std::terminate() (15.5.1).

Хотя вбрасывание выражение был перемещен в свою собственную функцию, во время выполнения исключение все еще обрабатывается, поэтому оно все еще работает:

#include <iostream>

void bar()
{
try {
throw;
}
catch (int x) {
std::cerr << "Damn " << x << "!\n";
}
}

void foo()
{
try {
throw 42;
}
catch (...) {
bar();
}
}

int main()
{
foo();
}

// Output: Damn 42!

(живое демо)

5

Другие решения

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

Обратите внимание, что звонит ваш CatchErrors() позвоню std::terminate() если он вызывается вне блока обработки исключений. Это требуется от throw; заявление, если не обрабатывается исключение.

Только не надейтесь на технику слишком сильно. Лучше проектировать большинство ваших функций с некоторыми гарантиями безопасности исключений (т. Е. Они не будут работать со сбоями, если выдается исключение, и они его не вызывают). Это дает больше возможностей для централизации обработки исключений (например, в main()) вместо того, чтобы иметь множество различных функций, которые должны обрабатывать исключения в отдельности. Это уменьшает необходимость повторного использования кода обработки исключений, поскольку большинство исключений будет обрабатываться только в одном месте.

3

По вопросам рекламы [email protected]