Несколько блоков catch или один с dynamic_cast? - PullRequest
2 голосов
/ 11 июня 2009

У нас есть иерархия классов исключений - есть класс GenericException и несколько классов, которые вытекают из него. GenericException полиморфный - у него есть виртуальный деструктор.

Один из производных классов FileException выдается для указания ошибок при манипулировании объектами файловой системы. FileException имеет GetErrorCode() метод, который возвращает код, указывающий, что на самом деле пошло не так.

Иерархия уже существует, я не могу ее изменить, поэтому об этом не может быть и речи.

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

Теперь у меня есть ситуация, когда набор операторов может генерировать исключение, которое гарантированно будет получено из GenericException. Если это FileException и , тип ситуации ошибки - «файл не найден». Я хочу ничего не делать, в противном случае я хочу показать сообщение об ошибке, а затем в любом случае считаю, что исключение обработано.

У меня есть два варианта - любой:

} catch( GenericException* e ) {
    FileException* fileException = dynamic_cast<FileException*>( e );
    if( fileException == 0 || fileException->GetErrorCode() != FileNotFound ) {
        ShowMessage( e );
    }
    delete e;
}

или этот:

} catch( FileException* e ) {
    if( fileException->GetErrorCode() != FileNotFound ) {
        ShowMessage( e );
    }
    delete e;
} catch( GenericException* e ) {
    ShowMessage( e );
    delete e;
}

Я предпочитаю первый, потому что он уменьшает дублирование кода. Но я слышал мнение, что, поскольку C ++ допускает выборочные блоки catch (как во втором варианте), я не должен использовать dynamic_cast - выборочные блоки catch для этого не нужны.

Какой вариант лучше? В чем может быть причина не первый вариант здесь?

Ответы [ 4 ]

4 голосов
/ 11 июня 2009

Вы никогда не должны бросать указатели. Всегда бросайте значения и ловите константой Рекомендации. Почти никогда невозможно правильно очистить динамически размещенный объект исключения.

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

3 голосов
/ 11 июня 2009

Я бы предпочел второй.

Если вас беспокоит дублирование, знаете ли вы что-то, что называется «диспетчер исключений»? Если вы найдете много мест, где вам нужно выполнить одинаковую обработку перехвата, вы можете поместить все это в одну функцию и вызвать эту функцию из блока перехвата (...).

, например

void fn()
{
    try
    {
        MightThrow();
    }
    catch (...)
    {
        ExceptionHandler();
    }
}

void ExceptionHandler()
{
    try
    {
        throw;
    }
    catch( FileException* e ) {
        if( fileException->GetErrorCode() != FileNotFound ) {
            ShowMessage( e );
        }
        delete e;
    } catch( GenericException* e ) {
        ShowMessage( e );
        delete e;
    }
}

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

Редактировать: Вы должны убедиться, что ExceptionHandler не вызывается, когда не обрабатываете исключение, в противном случае возникнет много проблем: связанный вопрос

2 голосов
/ 11 июня 2009

Второй вариант является «лучшим», если переписать его с помощью const &; -)
Я считаю, что второй намного чище, чем первый, он ясно указывает на то, что вы хотите.

0 голосов
/ 26 ноября 2009

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

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