Exceptions framför "manuell" felhantering?

Permalänk

Exceptions framför "manuell" felhantering?

När är exceptions att föredra framför vanlig "manuell" felhantering?

Jag har programmerat mest i C++ och jag har undvikit att använda exceptions nästan helt och hållet. Men jag undrar om det är så dumt egentligen? På jobbet kodar jag nästan uteslutande i C men jag har märkt att man ofta skapar try-catch-liknande konstruktioner med hjälp av olika makron och hjälpfunktioner. Jag inbillar mig dessutom att det blir enklare att skriva felhanteringen och cleanupkoden på det sättet.

Jag har fått för mig att många liksom jag undviker exceptions, men jag undrar, vad finns det egenligen för för- och nackdelar om man ställer det mot manuell felhantering med returvärden o.s.v.?

Jag har läst runt lite ett antal gånger tidigare men nu har jag glömt det mesta. Jag ser gärna en diskussion om prestandaaspekten också.

Tack.

Tillägg:
Jag tror att vi kommer att komma fram till att en blandning är det bästa. Exceptions lämpar sig säkert bättre för vissa saker. T.ex. om något går fel i en konstruktor? Men när vill man använda vanlig felhantering med returkoder? Om det är något som förväntas kunna gå fel ofta? Om det inte är så exceptionellt så att säga?

Permalänk

Kommer ihåg att jag läste på MSDN för ett tag sen att try-catch var långsammare...

Istället för att köra try och catcha nullreferenceexception skulle man kolla ifall det var null innan. Detta var då ifall det skulle ske ofta problemet, och inte bara när något gått fel

Visa signatur

Asus Striker II Extreme / XFX Geforce GTX 280 / Q9450 @ 3.6GHz/ TRUE Noctua 120/ 4x1GB Corsair TWIN3X2048-1333C9DHX / X25-M G2 80gb Velociraptor / Win 7 Ultimate x64/ Antec P190

MovieDatabase

Permalänk
Hedersmedlem

Bäst är att inte göra fel. Kan det inte undvikas är det förmodligen klokt att ta hand om de enkla fallen och spara try/catch till oförutsägbara och sällsynta fel. Viss prestandaförsämring får man räkna med. Här har någon testat i c#: http://www.chinhdo.com/20080226/try-catch-blocks-performance/

Permalänk
Medlem

Prestanda kommer i de flesta applikationer i andra hand när det gäller den här typen av problem. I modernare språk som C#, Java och Python t.ex., är det att föredra att kasta undantag om något går fel. En hyfsad förklaring till fördelen med undantag hittas här.

Sen ska man skilja på fel (Error) och undantag (Exception). Ett Error innebär i stort sett att något oförutsägbart och ohanterbart har inträffat, som inte går att återhämta sig från. Dessa ska med andra ord inte tas om hand av try/catch, då det inte går att reparera skadan. Exceptions ska man kunna förutse, t.ex. att en fil inte hittas, att man försöker läsa positioner i en array som inte finns, att man försöker göra om en icke-alphanumerisk sträng till siffror, o.s.v.

Man slipper även en massa if-satser för att se om ett objekt som returneras inte innehåller null (brukar tyvärr vara ett standardförfarande om något går fel i en metod som ska returnera ett objekt).

Jag föredrar med andra ord att hantera förutsägbara fel med Exceptions, och jag kan inte förstå varför man vill returnera felkoder och null-objekt istället. Men så utvecklar jag inte heller i C, så kanske är mitt inlägg helt överflödigt...

Permalänk

Om man skriver en funktion som kommer att användas av andra och därmed inte kan räkna med att få giltiga inparametrar, så är det egentligen bara inparametrarna, externa händelser/resurser, samt implementationsmisstag i funktionen som kan skapa "fel" som jag ser det.

Skulle man då kunna säga att det är bäst att returnera en felkod om funktionen får felaktig input och kasta ett undantag i fall av t.ex. en misslyckad filöppning/skrivning? Har man gjort ett implementationsmisstag kan man kanske fånga det också med try-catch i klientkoden om man har tur..? Man skulle ju kunna hantera misslyckade resursallokeringar med felkoder också?

Angående länken med prestandatestet i C# så verkar det ju inte som något bra kodexempel, men det är nog lätt att råka skapa liknande kod i ett mer komplicerat projekt. Det gäller helt enkelt att ha try-catch-blocken väldigt "högt upp" i callstacken antar jag. Fast då förstör man ju också möjligheten att återhämta sig från felet och fortsätta eftersom man högre upp inte har en aning om detaljen som gick fel.

Redigering:
bjornie: Jag är intresserad av fler språk än C/C++. Det låter lite konstigt att använda exceptions till förutsägbara fel i mina öron. Det är ju tänkbart, men det känns inte som att det är menat att användas på det sättet.

Permalänk
Glömsk

En relevant artikel:

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xm...

Framförallt:

Citat:

More generally, exceptions make the control flow of programs difficult to evaluate by looking at code: functions may return in places you don't expect. This results maintainability and debugging difficulties. You can minimize this cost via some rules on how and where exceptions can be used, but at the cost of more that a developer needs to know and understand.

Visa signatur

...man is not free unless government is limited. There's a clear cause and effect here that is as neat and predictable as a law of physics: As government expands, liberty contracts.

Permalänk

* Some third-party C++ libraries use exceptions, and turning them off internally makes it harder to integrate with those libraries.

Varför listas det som en fördel?

En liten del av mig tänker nu "Ah google använder inte exceptions, då behöver jag inte ändra mina vanor".

Men för att återgå till att vara seriös; Just att det kan vara svårt att förstå och förutspå programflödet känns som en väldigt stor nackdel. För som jag ser det är det stora syftet med exceptions att förenkla samt snygga upp och göra koden mer lättläst. Visst, om man utgår från att allting går som det ska så är det ju mer lättläst, men att försöka förstå flödet när något går fel verkar vara svårt och i så fall anser jag det inte värt att börja använda exceptions nu när jag redan är van vid och bekväm med att använda returvärden.

Permalänk
Medlem

Förutsägbara fel kanske är fel(!) uttryck, men jag menar alltså i fall där man kan anta att ett undantag uppstår - t.ex. vid filläsning (kasta ett Exception upp i hierarkin om filen inte finns), nummerformatering av strängar (kasta ett Exception om strängen innehåller andra tecken än siffror), o.s.v.

Om du läste C++-länken som Psionicist gav bör du även läsa samma styleguide för Python. Som du ser skiljer det även mellan olika språk på hur man bör hantera undantag. Jag som hellre programmerar i Java är ju "uppfödd" med Exceptions, det kanske är därför jag förespråkar dem framför returkoder (jag står inte ut med alla if-satser helt enkelt!).

Permalänk
Citat:

Ursprungligen inskrivet av Antonovskij
* Some third-party C++ libraries use exceptions, and turning them off internally makes it harder to integrate with those libraries.

Varför listas det som en fördel?

Om det blir svårare att integrera med de biblioteken för att man har stängt av exceptions ( som de skrev), måste det ju vara en fördel att HA exceptions?

Visa signatur

Asus Striker II Extreme / XFX Geforce GTX 280 / Q9450 @ 3.6GHz/ TRUE Noctua 120/ 4x1GB Corsair TWIN3X2048-1333C9DHX / X25-M G2 80gb Velociraptor / Win 7 Ultimate x64/ Antec P190

MovieDatabase

Permalänk

Jo det är sant, men det är ju en nackdel med exceptions rent allmänt tycker jag, att det kan skapa såna inlåsningsproblem!

Redigering:
Fast jag antar att det beror på vilken synvinkel man har. Returkoder har ju samma inlåsningseffekt. Men jag tycker ändå det är konstigt att se det som en fördel med exceptions.

Redigerar igen:
Jag inser nu att de inte snackar om konceptet exceptions i allmänhet, utan snarare ur ett rent praktiskt perspektiv, så som du beskrev det KurreKula.

Angående det som bjornie skrev så tycker jag att man egentligen inte borde dela upp diskussionen för olika språk, utan hålla den generell och snacka om exceptions som koncept. Jag antar att anledningen till att Google ger olika riktlinjer för olika språk har mer att göra med att följa språkets tradition eller typiska användningsstil. D.v.s. i t.ex. Python använder de flesta exceptions och därför rekommenderar de att man själv gör det också. Sen om det verkligen är bra att använda exceptions i Python är kanske en annan fråga?

Permalänk
Medlem

Jag kör stenhårt på exceptions i C++; man slipper väldigt många checkar och koden blir snyggare och lättare. RAII utan exceptions kan ju inte vara så kul heller, vad ska man göra om en constructor misslyckas initiera objektet? Typ sätta en zombieflagga som måste checkas senare. Om man kastar ett exception i en constructor försvinner objektet som håller på att konstrueras vilket leder till att man endast kan ha fungerande objekt i omlopp.

Ingen idé att prata om prestandan direkt; den påverkas oftast bara när man throw:ar ett objekt vilket borde vara väldigt sällan/aldrig. Inte ens det behöver man bry sig om på dagens datorer. Det blir dock lite extra information i stackframesen, men det är lätt värt det -- man slipper ju alla if-check:ar!

En dålig sak med exceptions är att all kod måste vara kompilerad med exceptions aktiverade, om man försöker kasta ett exception genom ett tredjepartsbibliotek (typ från en callbackfunktion) som inte är kompilerat med exceptions i åtanke så har jag för mig att man hamnar i undefined behavior, om man har tur blir det en std::terminate.

1. RAII + exceptions + referenser istället för pekare = nice.
2. om du try...catch:ar överallt gör du fel

Visa signatur

Min utvecklingsblogg: http://blog.iostream.cc

Permalänk

Intressant. Lite drygt om man skriver ett bibliotek själv som använder exceptions, så att det skapar problem för de som använder biblioteket.

Om man t.ex. skulle vilja tillhandahålla ett C-api i sitt bibliotek som är implementerat i C++, skulle man då kunna använda exceptions internt i biblioteket men dölja det utåt sett genom att konvertera eventuella exceptions till felkoder i C-api-lagret? Eller är det omöjligt av tekniska skäl? Jag är inte så insatt i hur exceptions fungerar under huven, det är därför jag frågar.

Permalänk
Medlem

Det skulle fungera bra, har för mig att jag sett en del libs som faktiskt gör så.

Error codes har en till fördel över exceptions i C++; det är lättare att se vilka fel en funktion kan få. Det blir då lite lättare att utföra unit testing samt kanske lättare att få ett grepp om vad funktionen gör, vilket är hyffsast viktigt för ett bibliotek.

Försöker täcka alla baser här med både för- och nackdelar, men fördelarna väger lätt över så skönt att slippa all felhantering som förslummar koden.

Visa signatur

Min utvecklingsblogg: http://blog.iostream.cc

Permalänk

Men när/var tycker du/ni att man ska använda try-catch då? Spontant tänker jag mig att man lägger det i main() (om man skriver ett program) eller motsvarande för att fånga upp alla undantag som man inte kan återhämta sig ifrån, men att man ändå försöker fånga vissa exceptions som man eventuellt kan återhämta sig ifrån på de ställen där det går?

Eller hur går tänket?

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Antonovskij
Men när/var tycker du/ni att man ska använda try-catch då? Spontant tänker jag mig att man lägger det i main() (om man skriver ett program) eller motsvarande för att fånga upp alla undantag som man inte kan återhämta sig ifrån, men att man ändå försöker fånga vissa exceptions som man eventuellt kan återhämta sig ifrån på de ställen där det går?

Eller hur går tänket?

Nja, en stor try-catch runt hela din kod är väl onödigt; obehandlade exceptions får väl programmet att avslutas "korrekt" ändå?

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av You
Nja, en stor try-catch runt hela din kod är väl onödigt; obehandlade exceptions får väl programmet att avslutas "korrekt" ändå?

Man kan ju ha det om man vill visa en meddelanderuta för användaren eller nått. Man behöver inte; om ett exception går utanför main kallas std::terminate.

Try...catch bör sättas där man kan hantera felet på ett vettigt vis, t ex om en path misslyckas att initieras kan man försöka med en fallback eller nått sånt. Då är det extra viktigt att man städar upp saker i destructors.

Visa signatur

Min utvecklingsblogg: http://blog.iostream.cc

Permalänk
Medlem

En god tumregel för C++ är att exceptions ska användas om man också använder RAII. Annars inte.

Visa signatur

"Nothing is impossible because impossible itself says I M Possible..."

Permalänk
Medlem

Man bär vara lite förskiktig med exceptions i c++ i konstruktorer, eftersom om du kastar en exception från konstruktorn kommer destruktorn inte köras. En konstruerad klass är i cpp en klass där konstruktorn körts klar. Kan dock komma att formuleras om i C++0x så att det är färdigkonstruerad om _NÅGON_ konstruktor körts klart.

All stack-unwinding-kod kan dessutom ta mycket minne, så om man arbetar i en begränsad miljö kan det vara bra om man är försiktig.

Visa signatur

void@qnet
teeworlds, stålverk80, evil schemer, c, c++
Languages shape the way we think, or don't.

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av jdv
Man bär vara lite förskiktig med exceptions i c++ i konstruktorer, eftersom om du kastar en exception från konstruktorn kommer destruktorn inte köras.

Destruktorn kommer att köras på alla medlemsobjekt som hunnit konstrueras, bara för att göra det tydligt.

Visa signatur

Min utvecklingsblogg: http://blog.iostream.cc