На вопрос, как нужно выбрасывать исключения, есть два мнения:
1) throw CMyException(...)
2) throw new CMyException(...)
И то и то работает. Но во втоом случае приходится явно удалять экземпляр исключения в секции catch:
try {
...
throw new CMyException(...);
} catch(CMyException *exc)
{
...
delete exc; // Ну или там в большинстве случаев — exc->Delete(), которая вызывает delete this;
}
Второй подход вроде как хуже из-за дополнительной необходимости удалять исключение. Или это фича?
Здравствуйте, Borisman, Вы писали:
B>На вопрос, как нужно выбрасывать исключения, есть два мнения: B>1) throw CMyException(...) B>2) throw new CMyException(...)
B> B>И то и то работает. Но во втоом случае приходится явно удалять экземпляр исключения в секции catch:
Угу. Первый чуть медленнее, поскольку выброшенный CMyException будет неявно копироваться при передаче из try-блока в catch.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, Borisman, Вы писали:
B>>На вопрос, как нужно выбрасывать исключения, есть два мнения: B>>1) throw CMyException(...) B>>2) throw new CMyException(...)
B>> B>>И то и то работает. Но во втоом случае приходится явно удалять экземпляр исключения в секции catch:
ГВ>Угу. Первый чуть медленнее, поскольку выброшенный CMyException будет неявно копироваться при передаче из try-блока в catch.
Не знаю, не проверял, но при втором много потенциальных взможностьей упустить память — пример
try
{
throw new CMyException();
}catch(...)
{
//попасть мы сюда попали, а память освобождать как?
}
Пример несколько надуман, но если нижележащий код кидает в try указатель, а ты об этом не знаешь, то найти этот лик в памяти будет очень проблематично.
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, Borisman, Вы писали:
B>>На вопрос, как нужно выбрасывать исключения, есть два мнения: B>>1) throw CMyException(...) B>>2) throw new CMyException(...)
B>> B>>И то и то работает. Но во втоом случае приходится явно удалять экземпляр исключения в секции catch:
ГВ>Угу. Первый чуть медленнее, поскольку выброшенный CMyException будет неявно копироваться при передаче из try-блока в catch.
Это если напишешь catch(CMyExeption). А ты так не пиши, ты пиши catch(CMyExeption&) как все нормальные люди.
Вообще первый способ (с new) не просто кривой, а очень кривой. Во первых, почти гарантирована утечка памяти — кто-нибудь либо не поймает, либо не удалит. Например в случае, если исключение попадает в блок catch(...) откуда ты узнаешь, что нужно сделать delete CMyExeption.
Во вторых, страдает столь любимая всеми нами производительность. Операция new — вещь в этом смысле очень дорогая...
Здравствуйте, Borisman, Вы писали:
B>>На вопрос, как нужно выбрасывать исключения, есть два мнения: B>>1) throw CMyException(...) B>>2) throw new CMyException(...)
B>> B>>И то и то работает. Но во втоом случае приходится явно удалять экземпляр исключения в секции catch:
ГВ>Угу. Первый чуть медленнее, поскольку выброшенный CMyException будет неявно копироваться при передаче из try-блока в catch.
Строго говоря, первый способ медленнее на передаче. Второй способ заторомозит при создании объекта-исключения, чем скорее всего сожрёт все "выигрыши". (псхпп grs)
Кстати, второй способ менее безопасен, поскольку new сама по себе может стать источником исключений.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, grs, Вы писали:
grs>Это если напишешь catch(CMyExeption). А ты так не пиши, ты пиши catch(CMyExeption&) как все нормальные люди.
Верное замечание! Большое спастбо, чуствуется, что соображает головой человек. Собственно, так и надо было мне первый пример написать, но я решил упростить.
Вот только одна закавыка: я толком не знаю, как раскручивается стек при ислючении, но тут разница между двумя подходами в том, где именно лежит все исключение-объект. В первом случае в стэке лежит он весь, а во втором — только указатель. Интересно, что проще для компилятора — раскрутить стек так, чтоб доступен был указатель (4 байта) или весь объект (много байтов).
Вообще-то я довольно много где видал именно второй способ выброса исключений. В первый раз увидел его в здоровенном финансовом приложении HPR. Очень меня это сбило с панталыку — глупые программеры того проекта утверждали, что если выбрасывать стековый объект, то при раскрутке стека он того....удалится в общем. Но потом, хорошенько подумав, я решил, что вроде-как не должен. Ведь делаем же мы вещи типа throw "приветик!" — и ниче...все корректно...
Еще есть подозрение, что просто не все компиляторы одинаково исключения обрабатывают (вспомним, что в старых версиях компиляторов С++ они вообще не везде были) и где-то как-то по разному работает выбрасывание стековых объектов. А вот динамические объекты типа работают....
Здравствуйте, Borisman, Вы писали:
B>На вопрос, как нужно выбрасывать исключения, есть два мнения: B>1) throw CMyException(...) B>2) throw new CMyException(...)
Если ты будешь передавать исключение дальше, да еще, завернув его в другое, то, возможно, второй подход будет лучше. Но я так никогда не делаю. И вообще не понимаю, суть обсуждения производительности блоков try-catch. Кому интересно, насколько быстро моя программа может сбоить???
Никогда не используй try-catch для программирования логики. А если ты это сделал, то не ломай голову над производительностью программы. Одно другое исключает. Вот так.
B>Вообще-то я довольно много где видал именно второй способ выброса исключений. В первый раз увидел его в здоровенном финансовом приложении HPR. Очень меня это сбило с панталыку — глупые программеры того проекта утверждали, что если выбрасывать стековый объект, то при раскрутке стека он того....удалится в общем.
Чем тяжелее бред, тем труднее на него реагировать...
А вообще, есть книжки Страуструпа (естественно) и Мейерса, где все расписано. Надо просто достать и прочитать внимательно. А резюме такое:
1) выбрасывается ТОЛЬКО стековый объет (НИ В КОЕМ СЛУЧАЕ НЕ УКАЗАТЕЛЬ)
2) перехватывается ССЫЛКА (не значение!).
Re[4]: Зачем надо throw new CMyException
От:
Аноним
Дата:
11.03.03 12:32
Оценка:
Здравствуйте, Borisman.
Хотелось бы отметить, что у передачи объекта-исключения указателем есть и определенные преимущества (не умаляя недостатков ).
Например, при передаче значением выполнить что-то вроде InnerException в .Net (т. е. обернуть одно исключение другим, так что исходное исключение становится причиной исключения на более высоком уровне абстракции) можно, но становится некрасиво.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Ведмедь, Вы писали:
В>>Видимо имелос ввиде то что try/catch вызывает некоторый провал в производительности.
А>... и, что еще более важно, в прозрачности и сопровождаемости кода.
Ну не всегда. в некоторых случаях IMHO прозрачней как раз через try/catch ( например, выход из N вложенных циклов )
К>Если ты будешь передавать исключение дальше, да еще, завернув его в другое, то, возможно, второй подход будет лучше. Но я так никогда не делаю. И вообще не понимаю, суть обсуждения производительности блоков try-catch. Кому интересно, насколько быстро моя программа может сбоить???
Кстати не совсем верно. В данном вопросе да, производительность значения не имеет. Я тоже считаю, что если произошло исключение, то обработать его в 90 процентов случае время есть и можно уже не торопиться Но факт в том что try/catch не в лучшей сторону влияет на производительность, не зависимо от того, происходит или нет исключение. А вот это не приятно.
Да пребудет с тобой Великий Джа
Re[6]: Re[2]: Зачем надо throw new CMyException
От:
Аноним
Дата:
11.03.03 16:41
Оценка:
Здравствуйте, Ведмедь, Вы писали:
В>>>Видимо имелос ввиде то что try/catch вызывает некоторый провал в производительности.
А>>... и, что еще более важно, в прозрачности и сопровождаемости кода.
В>Ну не всегда. в некоторых случаях IMHO прозрачней как раз через try/catch ( например, выход из N вложенных циклов )
Вы будете смеяться, но goto еще никто не отменял. А избежание goto — не самоцель.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Ведмедь, Вы писали:
А>Вы будете смеяться, но goto еще никто не отменял. А избежание goto — не самоцель.
goto не сделаешь из вложенной функции, кроме того в зависимости от типа кидаемого исклюения обработка может происходить в разных местах.
пример —
void CheckSome( int a )
{
if( a = 0 )
throw (int)1;//завершили
}
void SomeFunc()
{
try
{
for(...)
...
for(..)
{
CheckSome( a );
}
}catch( int i )
{
printf( "some var = %d", i );
}
}
Да пребудет с тобой Великий Джа
Re[8]: Re[2]: Зачем надо throw new CMyException
От:
Аноним
Дата:
11.03.03 17:10
Оценка:
Здравствуйте, Ведмедь, Вы писали:
В>goto не сделаешь из вложенной функции, кроме того в зависимости от типа кидаемого исклюения обработка может происходить в разных местах. В>пример —
В>
В>void CheckSome( int a )
В>{
В> if( a = 0 )
В> throw (int)1;//завершили
В>}
В>void SomeFunc()
В>{
В>try
В>{
В> for(...)
В> ...
В> for(..)
В> {
В> CheckSome( a );
В> }
В>}catch( int i )
В>{
В> printf( "some var = %d", i );
В>}
В>}
В>
Ой, какой бандитизм! Ничего не ясно.
Может, так?
bool CheckSome( int a )
{
return a = 0;
}
void SomeFunc()
{
for(...)
...
for(..)
{
if (CheckSome( a )) goto found;
}
found:
printf( "some var = %d", i );
}
он того....удалится в общем.
grs>Чем тяжелее бред, тем труднее на него реагировать...
grs>А вообще, есть книжки Страуструпа (естественно) и Мейерса, где все расписано. Надо просто достать и прочитать внимательно. А резюме такое: grs>1) выбрасывается ТОЛЬКО стековый объет (НИ В КОЕМ СЛУЧАЕ НЕ УКАЗАТЕЛЬ)
Выбрасывается всегда копия.
class EEE
{
private:
EEE(const EEE&); // закоментировать, чтобы откомпилилось
};
void f()
{
throw EEE();
}
int _tmain(int argc, _TCHAR* argv[])
{
f();
return 0;
}
grs>2) перехватывается ССЫЛКА (не значение!).
только если использовать синтаксис по ссылке (catch(some&)).
Приветствую!
> На вопрос, как нужно выбрасывать исключения, есть два мнения: > 1) throw CMyException(...) > 2) throw new CMyException(...)
[...skipped...] > Второй подход вроде как хуже из-за дополнительной необходимости удалять > исключение. Или это фича? > Бойцы, у кого какое мнение?
Замечательный вопрос. Я буквально на днях всерьёз озаботился этой проблемой.
После некоторых раздумий я реализовал решение, коим весьма теперь доволен.
Все проблемы с автоматическим удалением исключения в нём решены, а также
добавлена возможность "вложенности" исключений в стиле .NET.
void UserFunc()
{
try
{
LibraryFunc();
}
catch (CExceptionPtr& e)
{
CException* pe = e.get();
while (pe)
{
printf("%s", pe->GetMessage()); // выводим стек ошибок
pe = pe->GetInnerException();
}
}
}
Самое главное, что код абсолютно безопасен (я так думаю во всяком случае
в плане возможных утечек памяти. Т.е. не напрягаясь делаем new, и не вспоминаем
о delete Что принципиально отличает это решение от того, что есть в MFC.
Также мы можем свободно передавать исключения из потока в поток, т.е. для этого
их не нужно клонировать
Теперь минусы: единственным отрицательным моментом, на мой взгляд, является
то, что для каждого нового класса исключений нужно не забыть сделать один
дополнительный typedef, благодаря которому появляется возможность пользоваться
приведением к базовому классу в catch. В вышеприведённом коде видно, что мы
ловим более абстрактное исключение, чем выбросили.