2010-04-26 7 views
5

Если деструктор выбрасывает C++ во время разматывания стека, вызванного исключением, программа завершается. (Вот почему деструкторы никогда не должны бросать в C++.) Пример:Выбрасывание нового исключения при метании старого исключения

struct Foo 
{ 
    ~Foo() 
    { 
     throw 2; // whoops, already throwing 1 at this point, let's terminate! 
    } 
}; 

int main() 
{ 
    Foo foo; 
    throw 1; 
} 

terminate called after throwing an instance of 'int' 

This application has requested the Runtime to terminate it in an unusual way. 
Please contact the application's support team for more information. 

Если наконец блок введен в Java из-за исключения в соответствующем Ьгу блоке, и, наконец, блок выбрасывает второе исключение, то первое исключение молча проглотил. Пример:

public static void foo() throws Exception 
{ 
    try 
    { 
     throw new Exception("first"); 
    } 
    finally 
    { 
     throw new Exception("second"); 
    } 
} 

public static void main(String[] args) 
{ 
    try 
    { 
     foo(); 
    } 
    catch (Exception e) 
    { 
     System.out.println(e.getMessage()); // prints "second" 
    } 
} 

Этот вопрос перешел мне на ум: может ли язык программирования обрабатывать несколько исключений одновременно? Будет ли это полезно? Вы когда-нибудь пропустили эту способность? Есть ли язык, который уже поддерживает это? Есть ли опыт такого подхода?

Любые мысли?

+7

Вы только что выбрали мой мозг исключение –

+1

Интересный вопрос. Я предполагаю, что «обрабатывая исключение», вы специально подразумеваете «раскручивание стека из-за исключения», а не «выполнение кода из блока catch». Последнее я бы назвал «обработкой исключения», но поскольку обработчик был обнаружен, вы можете исключить из него исключение (по крайней мере, на C++). –

+0

@Nick Вы правы, я редактировал заголовок.Если вы знаете лучший, не стесняйтесь менять его снова ;-) – fredoverflow

ответ

5

Подумайте с точки зрения управления потоком. Исключения в основном просто причудливые setjmp/longjmp или setcc/callcc в любом случае.Объект исключения используется для выбора определенного места для перехода к, например, адреса. Обработчик исключений просто рекурсирует по текущему исключению, longjmp ing до его обработки.

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

  • Объединить их в неповторимое исключение. Это означало бы разматывание всего стека и игнорирование всех обработчиков. Это создает риск каскада исключений, вызывающего совершенно случайное поведение.
  • Как-то построить их декартово произведение. Да правильно.

Методика C++ хорошо служит интересам предсказуемости.

0

Да, язык может поддерживать несколько исключений за раз; однако это также означает, что программистам необходимо одновременно обрабатывать множество исключений, поэтому существует определенная компромисс. Я слышал о языках, которые имеют это, хотя у меня возникли проблемы с составлением списка с моей головы; Я считаю, что LINQ или PLINQ могут быть одним из этих языков, но я не совсем помню. Во всяком случае, существуют разные способы исключения нескольких исключений ... одним из способов является использование цепочки исключений, либо заставляя одно исключение стать «причиной», либо «ранее предшествующим исключением» другого, или для исключения всех исключений в единственное исключение, представляющее тот факт, что были выбраны несколько исключений. Я предполагаю, что язык может также ввести предложение catch, которое позволяет сразу указывать несколько типов исключений, хотя это будет плохой выбор дизайна, ИМХО, поскольку количество обработчиков достаточно велико, как есть, и это приведет к взрыву catch, чтобы обрабатывать каждую возможную комбинацию.

2

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

3

Вы можете использовать исключения. http://java.sun.com/docs/books/tutorial/essential/exceptions/chained.html

try { 

} catch (IOException e) { 
    throw new SampleException("Other IOException", e); 
} 

Вы также можете попробовать поймать внутри вашего finnally тоже.

try{ 
}catch(Exception e){ 
}finally{ 
    try{ 
     throw new SampleException("foo"); 
    }catch(Exception e){ 
    } 
} 

Edit:

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

+0

Я верю, что C# также поддерживает цепочку. Интересно, может ли C++ 0x связывать цепочку? –

+0

Это разрешено во всех C++. Проблема C++, заявленная OP, не связана. – Potatoswatter

0

C++ std :: exception_ptr позволяет хранить исключения. Таким образом, должно быть возможно встраивать исключения из других исключений и создавать впечатление, что у вас есть стек на выброшенные исключения. Это может быть полезно, если вы хотите узнать основную причину фактического исключения.

+0

Это относится к исключениям, брошенным в блок 'catch'. Исключения, выброшенные из деструкторов во время размотки, - это другой зверь. – Potatoswatter

+0

Я знаю. Но вопрос не связан с этим, это лишь введение в окончательный вопрос. –

0

Одна ситуации, когда несколько брошенных исключения параллельно могут быть полезными, является модульным тестированием с помощью JUnit:

  • Если тест не пройден, то создается исключение (либо производится с помощью кода тестируемых или утверждения).
  • Каждый метод @After вызывается после теста, не прошел тест или не удалось.
  • Если метод After не работает, генерируется другое исключение.
  • Только исключение, вызванное методом After, отображается в моей среде IDE (Eclipse) для результата теста.

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

Эта проблема, вероятно, должна быть решена путем включения Eclipse всех уведомлений для данного теста, а не только последнего. Имея «параллельные исключения», где исключение из finally не проглотит одно из try, также решило бы эту проблему.

0

Если вы думаете об этом, ситуация, о которой вы описали, имеет Exception("First") в качестве основной причины Exception("second"), концептуально. Наиболее полезной вещью для пользователя, вероятно, было бы получение дампа стека, показывающего цепочку в этом порядке ...

0

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

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