многоточие опитайте catch на c++

Може ли многоточие try-catch да се използва за улавяне на всички грешки, които могат да доведат до срив? Има ли някакви аномалии?

try
{
//some operation
}
catch(...)
{
}

person ssk    schedule 12.10.2011    source източник
comment
Всички отговори имат малка неточност: в c++ можете да хвърлите всичко, не само изключения, четете отговорите така, сякаш всичко, което е хвърлено беше използвано вместо всички изключения.   -  person David Rodríguez - dribeas    schedule 12.10.2011
comment
Ако намерението ви е да добавите манипулатор за поемане на всичко, за да предотвратите срив на програмата си, моля, не го правете. Вместо това коригирайте грешките във вашия код.   -  person John Dibling    schedule 12.10.2011
comment
@David: Но това, което хвърляте, става изключение, дори ако е int(1);   -  person Martin York    schedule 12.10.2011


Отговори (4)


Не, ще хваща само C++ изключения, а не неща като segfault, SIGINT и т.н.

Трябва да прочетете и разберете разликата между изключенията на C++ и при липса на по-добра дума, сигнали в стил "C" (като SIGINT).

person John Carter    schedule 12.10.2011
comment
В зависимост от компилатора и неговите настройки, той може да улови SEH изключения и в Windows (които включват неща като нарушения на достъпа). - person Cat Plus Plus; 12.10.2011

Ако кодът в блока try/catch се срине по някакъв начин, програмата така или иначе е в състояние, което не може да се възстанови. Не трябва да се опитвате да предотвратите срива, най-доброто, което програмата може да направи, е просто да остави процеса да се срине.

"Аномалията" е във факта, че вашият код улавя само изключенията, а не грешките. Дори ако кодът е защитен от изключения (което може да не е така, ако се опитвате да заобиколите грешките му чрез блок try/catch), всяка друга вътрешна грешка може да доведе програмата до непоправимо състояние. Просто няма начин да защитите програмата от него.


Допълнение: вижте тази статия в „Старото ново нещо“ за някои прозрения.

person Vlad    schedule 12.10.2011
comment
Въпреки че това все още е удобно за регистриране. Просто не забравяйте да завършите блока catch с оператор throw;, за да продължите хвърлянето. - person Mooing Duck; 12.10.2011
comment
@MooingDuck: Не бих по-добре да правя логване в catchall-block. Никога не знаете колко точно е повредено състоянието на вашата програма и по-добре е да направите възможно най-малко, за да предотвратите например повреда на потребителските данни. - person Vlad; 12.10.2011
comment
@MooingDuck: да :-) Вижте статията, която цитирам. - person Vlad; 12.10.2011
comment
Добра статия. Имах доста спорове относно това как не може да навреди да се опита да се въведе, докато не осъзнах, че влизането в std::cerr в състояние на грешка може да презапише буфера на RIAA поток или междупроцесна памет, която след това ще бъде изчистена по време на размотаване на стека. Значи си прав. Минимизирайте нанесените щети. Не използвайте catch (...). - person Mooing Duck; 12.10.2011
comment
@MooingDuck: наистина на Visual C++ catch(...) улавя SE (!), така че програмата е потенциално в много лошо състояние. - person Vlad; 13.10.2011

Това е Catch All манипулатор.
Той улавя всички C++ изключения, хвърлени от блока try. Не улавя segfault и други сигнали, които причиняват срив на програмата ви.

Докато го използвате, трябва да поставите този манипулатор в края на всички други специфични манипулатори за улавяне или всички ваши изключения ще бъдат уловени от този манипулатор.

Лоша идея е да използвате catch all handler, защото той просто маскира вашите проблеми и скрива неспособността на програмите, като улавя всички (дори неразпознати) изключения. Ако се сблъскате с такава ситуация, по-добре оставете програмата да се срине и създайте дъмп за срив, който можете да анализирате по-късно и да разрешите корена на проблема.

person Alok Save    schedule 12.10.2011
comment
Това е страхотна идея за дърводобив. Просто не забравяйте да продължите хвърлянето с throw; - person Mooing Duck; 12.10.2011
comment
@MooingDuck: Всъщност не. Губите информацията за типа, всичко, което можете да регистрирате, е опа, изключение, съжалявам. По-добре е да хванете std::exception в манипулатора от най-високо ниво за това. - person Cat Plus Plus; 12.10.2011
comment
@CatPlusPlus: Влад ме убеди, че влизането в неизвестно състояние е опасно. Коментарът е оттеглен. - person Mooing Duck; 12.10.2011
comment
Мисля, че е по същество погрешно да се каже, че е лоша идея да се използва. Бих сравнил универсален манипулатор с катапултираща седалка във военен самолет. Да, предпочитате никога да не го използвате, но когато нещата се объркат достатъчно лошо, все още е по-добре да го използвате, отколкото да го яздите в пламъци. - person Jerry Coffin; 12.10.2011
comment
@JerryCoffin: Никой от отговорите всъщност не изглеждаше да посочва, че използването му всъщност не е добра практика, опитах се, може би думите не оправдават/предават това, което исках, но въпреки това се опитах да предам правилното нещо. И не Не знам дали потребителите гласуват според мозъка или мафиотския манталитет, но получих 3 гласа против, защото казах правилно, но не толкова популярно нещо. - person Alok Save; 12.10.2011
comment
@Jerry: погледнете blogs.msdn.com/b /oldnewthing/archive/2009/11/13/9921676.aspx поради някакво разсъждение защо правенето на нещо в catch_all е лошо нещо. Пример: изключението може да се е случило по средата на разпределението на блока на купчина, така че всеки опит за регистриране може да доведе до непредвидими неща (включително стартиране на назални демони). - person Vlad; 12.10.2011
comment
Да -- разбирам какво имате предвид и съм съгласен с основната идея, но ми се иска да е формулирана по-добре. И аз не мисля, че @Vlad е съвсем прав. Да, теоретично може да се провали напълно -- точно както всяко извикване на функция може да причини препълване на стека и да се провали ужасно. И двете обаче са полезни достатъчно често, за да бъдат полезни инструменти. - person Jerry Coffin; 13.10.2011
comment
@Jerry: вътре в клаузата catch(...) шансовете нещо да се е объркало са доста големи. По-специално, шансовете, че купчината е в непоследователно състояние или е взето глобално I/O заключване, са разумни. - person Vlad; 13.10.2011
comment
@Влад: Всъщност не. Клауза catch(...) се извиква само за C++ изключения. За да бъде извикан, стекът трябва да е достатъчно последователен, за да се проследи обратно, за да се намерят манипулаторите на catch. По пътя размотаването на стека ще (се опита да) унищожи местните жители. Това обикновено включва някои deletes, така че ако купчината наистина е повредена, вероятно ще излезе от операционната система, преди да бъде достигнат манипулаторът. В този манипулатор шансовете системата да е ужасно корумпирана всъщност са доста малки. Статията, която сте свързали, говори за SetUnhandledExceptionFilter -- което е коренно различна ситуация. - person Jerry Coffin; 13.10.2011
comment
@Jerry: Не съвсем. :) На Windows/Visual C++ catch(...) хваща SEH, който може да бъде хвърлен в доста неприятни моменти. (Така че няма толкова голяма разлика между catch(...) и SetUnhandledExceptionFilter.) Тук има коментар ТАКА предполага, че на Linux catch(...) може да улови сигнал (ако съм го разбрал правилно), но не можах да намеря никакви препратки за това в Интернет. - person Vlad; 13.10.2011
comment
@Vlad: Въпросът е с етикет C++. Улавянето на SEH се случи във VC++6, но това със сигурност не трябва да се бърка с C++. - person Jerry Coffin; 13.10.2011
comment
@Jerry: добре, Windows все още е най-популярната десктоп платформа, нали? Така че не можем да кажем, че VC++ не се брои. Но добре, трябва да призная, че това съображение е извън кулата от слонова кост на стандартния C++ (въздишка). (AFAIK поведението на catch е същото и във VC++ 2010.) - person Vlad; 13.10.2011
comment
@Vlad: Това е моята гледна точка: поведението на catch не е същото във VC++2010, или VC++2008, или нещо друго след VC++6. Възможно е да получите поведение, подобно на VC++6, ако желаете достатъчно силно, но това не се случва по подразбиране и не се е случвало от години. - person Jerry Coffin; 13.10.2011
comment
@Jerry: бързото гугълване ми намери връзка, което предполага, че при някои обстоятелства поведението през 2010 г. е все още същото. Когато кодирате част от голям проект, трябва да сте внимателни. - person Vlad; 13.10.2011
comment
@Vlad: Прочетохте ли свързаната статия? Съвпада точно с това, което казах: възможно е да получите това поведение, ако се опитате достатъчно, но това няма да се случи по подразбиране. Никой, чийто коефициент на интелигентност е по-висок от размера на шапката му, дори не би помислил да го направи, освен за да накара стария код, написан за VC++6 или по-стар, да работи (за достатъчно свободна дефиниция на работа). - person Jerry Coffin; 13.10.2011
comment
@Jerry: всъщност последният C++ проект, в който работех, беше компилиран с /EHa. Нашият архитект обаче не носеше шапката. (Може би защото е преобразуван от някакъв стар код.) - person Vlad; 13.10.2011

Той улавя всичко, което е хвърлено, не се ограничава до изключения. Той не обработва неща като твърдения за отстраняване на грешки в Windows, системни сигнали, грешки в сегментите.

TEST(throw_int) {
    try {
        throw -1;
    } catch (std::exception &e) {
        std::cerr << "caught " << e.what() << std::endl;
    } catch (...) {
        std::cerr << "caught ..." << std::endl;
    }
}

Хвърлянето на цяло число обаче наистина не се препоръчва. По-добре е да хвърлите нещо, което наследява от std::exception.

Все пак може да очаквате да видите нещо подобно като последно усилие за документиране на провала. Не се изисква някои приложения да бъдат много надеждни. Вътрешните инструменти може да струват повече, отколкото си струват, ако сте преминали през стъпките, за да ги направите по-добри от хакнати заедно глупости.

int main(int argc, char ** argv) {
    try {
        // ...
    } catch (std::exception &e) {
        std::cerr << "error occured: " << e.what() << std::endl;
        return 1;
    }
    return 0;
}
person Tom Kerr    schedule 12.10.2011