2012-06-08 2 views
86

, глядя на какой-то код, который я наткнулся на:певд зЬй :: исключение против броска станд :: исключение

throw /*-->*/new std::exception ("//... 

, и я всегда думал, что вам не нужно/не следует использовать new здесь.
Каков правильный путь, оба в порядке, если это так, то есть разница?

Кстати, из того, что я вижу, когда «grepping» с PowerShell boost libs никогда не используют throw new.

P.S. также я нашел код CLI, который использует throw gcnew. Это нормально?

+0

Я думаю, что 'throw gcnew' было бы полезно, например. если вы хотите, чтобы управляемый код поймал ваше исключение. Может ли кто-нибудь меня исправить? – jpalecek

+1

.Net имеет дело с исключениями указателем, поэтому бросить gcnew - это правильная вещь. –

+1

@SebastianRedl .Net «указатель» может быть неоднозначным? Хотя gcnew, конечно же, нет. 'System :: Exception', как правило, является ссылкой на управляемый объект на сборку мусора. Я всегда бросал «gcnew» и поймал «System :: Exception». Конечно, я все время использую 'finally' в C++/CLI, хотя не часто смешиваю с исключениями C++ в одном блоке' try', я не уверен, почему. –

ответ

72

Обычный способ исключения и исключения исключений заключается в том, чтобы выбросить объект исключения и уловить его ссылкой (обычно const). Язык C++ требует, чтобы компилятор сгенерировал соответствующий код для создания объекта исключения и правильно очистил его в соответствующее время.

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

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

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

+1

«бросить объект исключения» стек или куча моего друга? Стек или куча? (Может быть, я где-то смотрел на плохой глобальный пример) ой, а если стек, то в чем же смысл? –

+0

@ebyrob: Я не совсем уверен, о чем вы спрашиваете, но похоже, что вы хотите знать о хранении и/или жизни объекта исключения, на который можно ответить [здесь] (http://stackoverflow.com/вопросы/1654150/сфера-оф-исключения-объект-в-с). Если нет, вам может быть лучше задавать отдельный вопрос. –

26

Не нужно использовать new при исключении бросания.

Просто написать:

throw yourexception(yourmessage); 

и поймать как:

catch(yourexception const & e) 
{ 
     //your code (probably logging related code) 
} 

Обратите внимание, что yourexception следует извлечь из std::exception прямо или косвенно.

+5

Почему? почему бы не использовать 'new'? зачем вызывать 'yourexception' из' std :: exception'? – Walter

+0

Когда я ленив (что часто waaay), почему не «бросать std :: exception;» работать? g ++, похоже, не скомпилирует его ... –

+5

@ebyrob: 'std :: exception' - это тип, и вы не можете выкинуть * тип *, вы должны выбросить * объект *. Поэтому синтаксис должен быть следующим: 'throw std :: exception();' Это будет компилироваться. Теперь, как хорошо, это совсем другой вопрос. – Nawaz

21

Throwing new std::exception является правильным, если сайт вызова ожидает поймать std::exception*. Но никто не ожидает, что поймает указатель на исключение. Даже если вы документируете, что делает ваша функция, и люди читают документацию, они по-прежнему могут забыть и попытаться поймать ссылку на объект std::exception.

+25

Throwing 'new std :: exception' является правильным только в том случае, если сайт вызова ожидает, чтобы поймать указатель И ожидает, что он возьмет на себя управление выделением allocate. И никогда не будет случаев, когда вы будете вызывать функцию тем, что явно не улавливает правильный указатель ('catch (...)' или вообще не обрабатывается), иначе будет утечка объекта. Короче говоря, это можно приблизить как «никогда». –

+0

Любопытно, как этот ответ был принят, когда на самом деле это комментарий @ CharlesBailey *, это правильный ответ. –

+0

@John: Это тоже перешло мне в голову. Но я думаю, что один-два удара имеют хороший эффект, когда я даю сухую сводку, и Чарльз удивленно расширяет различные способы, с помощью которых люди могут забыть справиться с этим должным образом. Тем не менее, вы не получаете репутацию от голосованных комментариев. – Hurkyl

7

C++ FAQ имеет хорошую дискуссию по этому вопросу:.

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

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

+2

Как обычно, часто задаваемые вопросы часто задаются. Вы можете поймать по значению или ссылке. Указатель просто оказывается значением (которое вы улавливаете по значению или ссылке). Помните, что тип 'A' отличается от типа' A * ', поэтому, если я делаю' throw A() 'Я НЕ могу поймать' catch (A * e) ', поскольку он совершенно другой тип. –

+0

Эти ссылки сейчас сломаны. – spanndemic

+1

Я исправил ссылки @spanndemic – user1202136

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