2014-11-26 1 views
1

В C++, почему вы хотите перестроить исключение. Почему бы не позволить текущему блоку catch обрабатывать исключение. По каким причинам вы можете перестроить исключение в другой блок try/catch?Зачем исключать исключение

+5

Поскольку функция, содержащая текущий блок catch, не может выполнить свою задачу и хочет выбросить исключение, чтобы указать это. – gnasher729

+0

[Добро пожаловать в StackOverflow] (http://stackoverflow.com/tour)! Это домашнее задание? Если это так, вы можете захотеть [немного повторить свой вопрос] (http://meta.stackexchange.com/questions/10811/how-do-i-ask-and-answer-homework-questions/10812#10812). –

+3

Если это не ваша работа, чтобы справиться с этим, почему вы проглотили бы исключение? Например, если вы пишете структуру данных, которая должна выполнять специальную работу по восстановлению, когда объект генерирует исключение при вставке, вам нужно поймать исключение для выполнения специальной работы, но это не ваша прерогатива для обработки исключения, поскольку вы не представляете, что это значит в этом контексте. Вы перехватываете и реконструируете исключение, когда хотите выполнять работу, когда возникает исключение, но в противном случае исключение распространяется нормально. – Cameron

ответ

3

Исключение выбрасывается, когда функция не может выполнить свой контракт (что обещает вызывающий абонент). Когда функция вызывает другую функцию, которая генерирует исключение, существует четыре основных подхода к тому, как он может ответить:

  1. Поймайте исключение и обработать его. Это нужно делать только в том случае, если функция может выполнить свой контракт, несмотря на то, что это исключение. Если он ловит исключение, но не выполняет его контракт, он скрывает проблему из вызывающего кода.

  2. Разрешить исключение для распространения. Это должно быть сделано, если исключение не может быть обработано этой функцией (т. Е. Функция не может выполнить свой контракт, поскольку исключение было выбрано), и если исключение предоставляет соответствующую информацию вызывающему коду.

  3. Поймайте исключение, сделайте некоторую очистку и/или добавьте дополнительную информацию, и восстановите ее. Это должно быть сделано, если исключение не может быть обработано этой функцией, но перед его распространением необходимо выполнить некоторую очистку. Он также может предоставить дополнительную информацию для обработки/отладки исключения (я часто думаю о программисте как о последнем обработчике исключений).

  4. Поймать исключение и выбросить другое исключение (возможно, обертывание оригинала). Это должно быть сделано, если исключение не может быть обработано этой функцией, но другое исключение лучше выражает проблему вызывающему коду.

1

Почему бы не позволить текущему блоку задвижки обработать исключение. По каким причинам вы можете перестроить исключение в другой блок try/catch?

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

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

Пример:

void connect_and_notify(int connection_data) 
{ 
    try 
    { 
     create_network_connection(connection_data); // defined somewhere else 
     notify("connection open");     // same (notify event listeners) 
    } 
    catch(const std::runtime_error&) 
    { 
     notify("connection failed"); 
     throw; 
    } 
} 

код клиента:

void terminal_app_controller() 
{ 
    try 
    { 
     connect_and_notify(1); 
    } 
    catch(const std::runtime_error& err) 
    { 
     std::cerr << "Connection failed;\n"; 
     exit(1); // this is usually bad bad code but whatever 
    } 
} 

void ongoing_server_controller() 
{ 
    bool connected = false; 
    int connection = 1; 
    while(!connected) 
    { 
     try 
     { 
      connect_and_notify(1); 
      connected = true; 
     } 
     catch(const std::runtime_error&) 
     { 
      connection++; 
     } 
    } 
} 

В двух сценариях использования, то ошибка обрабатывается по-разному (connect_and_notify не имеет возможности узнать, что, но все же, на неверном он должен уведомить слушателей).

Каждая функция имеет другую политику для обработки исключения, и это означает разные блоки catch.

0

Я очень не люблю ничего подобное

catch (std::exception&) { 
    ... // do some cleanup 
    throw; 
} 

RAII является правильным решением этой проблемы. Даже:

catch (std::exception&) { 
    ... // do some logging here 
    throw; 
} 

может обрабатываться RAII, хотя он менее интуитивно понятен.

BUT - где I есть re -rown - любая ситуация, когда код третьей части (или поставщика) генерирует «общие» исключения с состоянием. Например, при регистрации сообщений телематики в базе данных я знаю, что часто получаю дубликаты копий одного и того же сообщения. Каждое сообщение имеет уникальный идентификатор, поэтому нарушение первичного ключа в моей БД является «невиновной» ошибкой, которую следует игнорировать без малейшего молчания.

К сожалению, используемая нами инфраструктура БД не создает конкретного исключения для нарушений ПК, поэтому нам нужно поймать общее dbexception и проверить, что его код причины должен решить, что делать. Следовательно:

catch (db::exception& e) { 
    if (e.reason != db::exception::reason::pk_violation) 
     throw; 
} 

Также, piwi указано внутреннее состояние. Пример может быть

for (;;) { 
    try { 
     ... 
    } 
    catch (some_exception& e) { 
     if (retry_count > 3) 
      throw; 
    } 
} 

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

Смежные вопросы