C++ a výjimka v destruktoru

ferren

Re:C++ a výjimka v destruktoru
« Odpověď #150 kdy: 08. 02. 2014, 22:27:04 »
1) Connection conn = mysqlpool.get();
hm normalne by clovek ocekaval ze pool cehokoli me spis vrati adresu a ne hodnotu ale budiz treba to tak je netusim jak je ta tva Conection deklarovana pripadne velka/slozita/konstruovana...

Tenhle způsob může být právě docela fajn. Ta instance se mu vytvoří pěkně přímo na zásobníku, takže ušetří za volání new/delete. Navíc s opuštěním bloku se ten objekt může i automaticky sám uklidit (vrátit spojení do poolu).

to ze se na poolove operaci nebude provadet zadne dynamicke new/delete beru za samozrejmost, k tomu vetsinou slouzi ty ruzne pametove ci kontextove pooly:-)
ono je taky fajn,pokud chces at nejaky program bezi dele nez tyden, tak se celkove vyvarovat jakyhkoli dynamickych alokaci,pokud je to principialne mozne....


ferren

Re:C++ a výjimka v destruktoru
« Odpověď #151 kdy: 08. 02. 2014, 22:48:04 »
jo a jeste neco, vetsinou se nepisou funkce/metody co vraci nejake navratove hodnoty pro srandu kralikum,vetsinou se pisi proto aby je nekdo kontroloval. da se tim vse docela jemne skalovat, od warningu pres error po fatal. resit vse humpolacky, s tim ze to zkusim a budu chytat vyjimky je desne nasilne a casto to sklouzava do generovani nic nerikajicich "internich chyb" protoze kdo by se pak pri handlovani vyjimky obtezoval dohledavat co konkrente selhalo a jaky byl duvod,ze?

Ivorne

Re:C++ a výjimka v destruktoru
« Odpověď #152 kdy: 09. 02. 2014, 15:10:46 »
Takže jaký je závěr? Výjímka v destruktoru působí u většiny implementací memory leak, takže nepoužívat?

RAII

Re:C++ a výjimka v destruktoru
« Odpověď #153 kdy: 09. 02. 2014, 15:24:20 »
Ne, exceptions v destruktorech sou nechutná prasárna. Nejde tady jen o ten memory leak, destruktory prostě nesmí NIKDY selhat (taky v nich nemá co selhat -> pokud teda nevymyslíš ňákou uber kravinu). PROTOŽE destruktor ti uvolňuje prostředky objektu (paměť, zámky, soubory, streamy). Někteří hold serou na RAII a implementujou si to po svim...

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #154 kdy: 09. 02. 2014, 15:47:47 »
Takže jaký je závěr? Výjímka v destruktoru působí u většiny implementací memory leak, takže nepoužívat?
Jednoduché odpovědi se tady bohužel nedočkáš. Závisí to na spoustě věcí.

Chceš vůbec používat výjimky? Ferren tu napsal dost příkladů, kdy se úplně nehodí.
Jak často budou lítat? Častější chyby je lepší řešit návratovými hodnotami. Chytat výjimky např. při každém parsování intu je nechutný opruz.
Budou ty házející objekty na haldě, nebo jenom na zásobníku? Pokud na zásobníku, tak se ten bug v delete neprojeví.
Vadí, že program výjimečně padne na hubu (std::terminate)? Jestli ne, tak klidně házej. Restart programu může být někdy nejjednodušší zotavení z chyby.
Vadí, že destruktor ve vzácných případech tu výjimku stejně nevyhodí (std::uncaught_exception)? Pokud jo, tak ten kód stejne v destruktoru být nemůže.


Ivorne

Re:C++ a výjimka v destruktoru
« Odpověď #155 kdy: 09. 02. 2014, 16:34:52 »
Tak já si stejně myslím, že výjimky jsou dobré akorát pro rapid develpoment a prototypování. Ale pokud by se člověk rozhodl používat výjimky, tak stejně je nejlepší říct si, že destruktor je házet nesmí. Když házíš výjimky v destruktoru, tak podle této diskuse: 1) nemůžeš používat stl, 2) nesmíš tyto třídy alokovat dynamicky a 3) stejně nemáš jistotu, že to bude fungovat (std:uncaught_exception).

Ta 1) a 2) se dají přežít, ale jestli to není příliš velká cena za něco, co bude člověk používat jen zřídka a to u věcí, které se stejně dají řešit jinak. Celkem rozumné řešení mi přijde to jak tu kdosi zmiňoval v kontextu flushování output bufferu - v destruktoru to chybu potlačí (maximálně zaloguje) a pokud chce programátor zvenku tu chybu sledovat, tak před destrukcí zavolá metodu flush(). To navíc umožní řešení problému i bez smazání nebo invalidace objektu.

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #156 kdy: 09. 02. 2014, 16:35:13 »
Kód: [Vybrat]
{
Connection conn = mysqlpool.get();
Transaction trn(conn);
Result res = trn.SELECT("*").FROM(...).....;
....
trn.commit();
}
Tohle je dobrý příklad kódu na rozbor, jestli je z těch destruktorů vůbec třeba házet. Zrovna tady to IMO není vůbec třeba. Proč?

~Transaction zavolá rollback. Nejspíš pouze v případě, že poslední metoda nebyl úspěšný commit. Může házet třeba, pokud vypadne spojení s databází (jak mi tady O.N. před časem napsal). Rozumné databáze v takovém případě udělají rollback samy. Takže destruktor vlastně udělal přesně to, co měl, ale stejně vyletí výjimka. Já bych tu chybu teda hlásil až ve chvíli, kdy by uživatel té knihovny to spojení chtěl použít znova. Pokud nechce, tak vypadlé spojení ničemu nevadí.

~Connection vrací spojení do poolu. Na samotném vracení objektu do poolu není co vyhodit. To je nějaký ten inkrement a přešoupnutí objektu mezi spojovými seznamy. Pokud se nepodaří zamknout mutex, nebo je ten pool nějak rozbitý, tak je to stejně fatální chyba pro celý proces. Může se házet třeba když to spojení nepůjde v budoucnu znova použít. Otázka je, proč by uživatele toho poolu měla tahle chyba zajímat. Pokud je spojení špatné, tak ho pool zavře a až bude potřeba, tak ho zkusí otevřít znova. Než bude znova potřeba, tak ta síť třeba zase naskočí.

Nemá cenu házet při jakékoliv chybě. Jen při takové, která zajímá uživatele. Uživatelem tady myslím i kus kódu, který používá ty objekty.

belzebub

Re:C++ a výjimka v destruktoru
« Odpověď #157 kdy: 09. 02. 2014, 16:53:33 »
...
splachovaci, a proto se musim branit: V C++ delam od r.1993, profesionalne od 1999. Naucil jsem se drive C++, nez C (ne, to neni protimluv - psat udrzovatelne a korektne velky projekt v C je neco jineho nez "nepouzivat tridy a templaty" v C++) a na C jsme presli (cely team) kolem roku 2008.
...

Zaujima prechod z C++ na C. Kedze s tym mas skusenosti prosim Ta mohol by si to trochu viac rozviest. Napr. aky velky projekt robite? Ako mate implementovane kontajnery (makrami, ...)?  Pouzivate vela makier? Nechyba vam obcas C++? Rychlost kompilacie je asi podstatne vyssia? Pouzivate GUI? Nemuseli ste si vyrobit objektovy system podobny GObject-u? Pouzivate GOTO (napr. ako nahrada vynimiek)? Kludne mi to mozes poslat ako PM, aby sme nespamovali toto vlako.

Jedna se o projekt toho typu o kterem se zminil "ferren" - neustale bezici system, kde neni vyzadovana ani tak nejvyssi rychlost, ale hlavne spolehlivost. Takze implementujeme presne to o cem "ferren" psal - jakakoliv chyba, ktera je "neopravitelna" (nejde forknout, nejde alokovat pamet, atd.) zpusobi spadnuti celeho jednoho procesu. Cela "architektura" je realizovana jednim procesem ktery spousti dalsi procesy, ktere spolu komunikuji pres local-unix-sockety. Nikde zadna sdilena pamet a zadne thready (byly, ale bylo s nimi vic problemu nez je zdravo - procesy + messages jsou sice "mene uzivatelsky pritulne", ale zato radove robustnejsi.
System je duplikovany, takze v pripade padu prebira praci jiny server, dokud nekdo neda puvodni do poradku.
Posledni verze napr. na vetsine produkcnich serveru bezi bez restartu dele nez rok.
Projekt neni ani tak velky co se tyce mnozstvi kodu, jako spise komponent - mame cca 40% kodu v C, 50% v pythonu, zbytek v plsql + nejake shell skripty a dokonce je nekde i nejaky legacy perl (nemluvim o GUI).
Tj. co se GUI tyce - ne, zadne gui, je to ciste "back-end", GUI dela jiny team.
Kontejnery - pouzivame GLib/GObject knihovny tam kde je potreba neco "trochu vysokourovnovejsiho".
Makra - pokud pominu ze GLib/GObject sam pouziva maker hodne, tak i my nejake pouzivame, ovsem ve vetsine pripadu se jedna o "lokalni" makra - pouzite v jednom souboru a nebo pro ruzna "DEBUG-mode zavisla" makra.
Co se "chybeni C++" tyce,  GObject (teoreticky) poskytuje dokonce i vic "objektovych" vlastnosti nez C++, ovsem za cenu neuveritelneho mnozstvi dosti oskliveho "boiler-plate" kodu. Vetsinu "vysokourovnovejsich" objektu tedy resime tak, ze je napiseme ve Vale (mozna si nekdo vzpomene ze jsem zde pred par dny pred valou varoval), ta je "zkompiluje" do C a pak pokracujeme dale upravami vygenerovanych souboru.
Pokud neni nutne pouzivat nejake "objektove" vlastnosti (napr.dedicnost) a staci neco jako "zapouzdreny objekt", pouzivame konstrukci s "opaque" struct, tj. v .h souboru je definovany jen "typedef struct SomeObject_ SomeObject;" a funkce pracujici s "SomeObject" - tim mame vzdy dvojici ".h" a ".c" souboru fungujicich jako urcita "zapouzdrena jednotka". To je asi hlavni bod "prechodu na C" a zaroven vyreseni problemu neexistence "namespace" v C - vetsina "discipliny" je o tom dodrzet urcita pravidla pro jmena funkci a nektere "povinne" funkce/makra (new, delete, cast, asserty)
Tj. pouzivame vedle sebe jak GObject objekty (odlisene prefixem) i "dumb" objekty (viz vyse). Rekl bych ze GObject objektu mame tak 5% a postupne je eliminujeme ("vyssi" funkcnost se presouva do pythonu a plsql).
GOTO pouzivame velmi silne, ovsem z 99% pouze pri osetrovani chyb pri "komplikovanejsi" konstrukci objektu k zaruceni pouze jednoho return-u a/nebo k zajisteni korektniho "uklidu" pri chybe v konstrukci objektu. Takze se da rict, ze v ramci jedne funkce GOTO do urcite miry supluje vyjimky.
Jinak na to co by mely byt vyjimky pouzivame GError.
Atd, atd.
Co se zkusenosti tyce - nejvetsi plus je spolehlivost - za posledni 3 roky jsme meli pouze jeden "zahadny bug", ktery se navic nakonec ukazal jako spatne nastaveni objektu z externi knihovny. Obecne muzu rici, ze debugovani Cckoveho kodu, i kdyz je ho vice, je mnohem snazsi, diky tomu, ze C-cko je primitivnejsi, tak je i vetsina chyb "jednodussich" - paradoxne jsme jeste nemeli memory leak nebo segfault v produkci - coz s C++ bylo celkem caste. Ja osobne to pricitam efektu, ktery jsem mockrat v ruznych variantach cetl na ruznych mistech - protoze debugovani je slozitejsi nez psani kodu, tak kdyz napisu kod tak chytry jak to jen dokazu, tak ho pak nedokazu debugovat.
Navic code-review je opet mnohem jednodussi, protoze neni nutne zjistovat zadne vnorene vyjimky, zadne pretizene operatory, a hlavne, kdo nekdy videl jak vypada hlaseni chyby kompilatoru z nekolikrat "zanoreneho" templatu, tak oceni ze temer kazda chyba je celkem zjevna.
Nekteri lide vyzdvihovali jako prednost veci jako: stabilni ABI (u C++ to je trochu horsi), dostupnost C kompilatoru pro snad kazdou existujici platformu (vcetne embedded) - coz myslim uz dnes neni moc pravda (a mozna to nebyla pravda ani v 2008).
Rychlost kompilace rozhodne JE plus - kompilace celeho C kodu je na mem notebooku pod 30 sekund - tehdejsi C++ varianta se kompilovala i pres 10 minut (ano, mel jsem pomalejsi pocitac) - ovsem diky modularite projektu to neni az takove plus jak by se mohlo zdat.

Abych jen nechvalil - jak jiz jsem zminil, hlavni nevyhodou je delsi kod a slozitejsi testovani (mame vicemene 99% kodu pokryto unittesty), kde je nutne pouzit trochu jine principy (klasicke mockobjekty definujici nejaky interface jdou s GObject pouzit, ale je to vesmes vice prace nez se vyplati). Rozhodne je nevyhoda i to, ze kazdeho noveho programatora je nutne "prevychovat", protoze kdyz nekdo napise v CV, ze "umi C", mysli tim v 99% ze umi C++ a tedy ze vlastne umi i C.

Jakub Galgonek

Re:C++ a výjimka v destruktoru
« Odpověď #158 kdy: 09. 02. 2014, 17:22:13 »
Tohle je dobrý příklad kódu na rozbor, jestli je z těch destruktorů vůbec třeba házet. Zrovna tady to IMO není vůbec třeba. Proč?

Tohle ale nebyl vůbec příklad na to, jestli je třeba z destruktorů házet výjimky  :)

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #159 kdy: 09. 02. 2014, 17:25:13 »
Tohle je dobrý příklad kódu na rozbor, jestli je z těch destruktorů vůbec třeba házet. Zrovna tady to IMO není vůbec třeba. Proč?

Tohle ale nebyl vůbec příklad na to, jestli je třeba z destruktorů házet výjimky  :)

To ne, ale o pár stránek dřív dal Ondřej Novák právě ten objekt Transakce jako příklad, kdy se hodí ty výjimky z destruktoru házet. Tak jsem si řekl, že ten kód rozeberu i z tohohle pohledu.

randolf

Re:C++ a výjimka v destruktoru
« Odpověď #160 kdy: 10. 02. 2014, 14:00:49 »
...
splachovaci, a proto se musim branit: V C++ delam od r.1993, profesionalne od 1999. Naucil jsem se drive C++, nez C (ne, to neni protimluv - psat udrzovatelne a korektne velky projekt v C je neco jineho nez "nepouzivat tridy a templaty" v C++) a na C jsme presli (cely team) kolem roku 2008.
...

Zaujima prechod z C++ na C. Kedze s tym mas skusenosti prosim Ta mohol by si to trochu viac rozviest. Napr. aky velky projekt robite? Ako mate implementovane kontajnery (makrami, ...)?  Pouzivate vela makier? Nechyba vam obcas C++? Rychlost kompilacie je asi podstatne vyssia? Pouzivate GUI? Nemuseli ste si vyrobit objektovy system podobny GObject-u? Pouzivate GOTO (napr. ako nahrada vynimiek)? Kludne mi to mozes poslat ako PM, aby sme nespamovali toto vlako.

Jedna se o projekt toho typu o kterem se zminil "ferren" - neustale bezici system, kde neni vyzadovana ani tak nejvyssi rychlost, ale hlavne spolehlivost. Takze implementujeme presne to o cem "ferren" psal - jakakoliv chyba, ktera je "neopravitelna" (nejde forknout, nejde alokovat pamet, atd.) zpusobi spadnuti celeho jednoho procesu. Cela "architektura" je realizovana jednim procesem ktery spousti dalsi procesy, ktere spolu komunikuji pres local-unix-sockety. Nikde zadna sdilena pamet a zadne thready (byly, ale bylo s nimi vic problemu nez je zdravo - procesy + messages jsou sice "mene uzivatelsky pritulne", ale zato radove robustnejsi.
System je duplikovany, takze v pripade padu prebira praci jiny server, dokud nekdo neda puvodni do poradku.
Posledni verze napr. na vetsine produkcnich serveru bezi bez restartu dele nez rok.
Projekt neni ani tak velky co se tyce mnozstvi kodu, jako spise komponent - mame cca 40% kodu v C, 50% v pythonu, zbytek v plsql + nejake shell skripty a dokonce je nekde i nejaky legacy perl (nemluvim o GUI).
Tj. co se GUI tyce - ne, zadne gui, je to ciste "back-end", GUI dela jiny team.
Kontejnery - pouzivame GLib/GObject knihovny tam kde je potreba neco "trochu vysokourovnovejsiho".
Makra - pokud pominu ze GLib/GObject sam pouziva maker hodne, tak i my nejake pouzivame, ovsem ve vetsine pripadu se jedna o "lokalni" makra - pouzite v jednom souboru a nebo pro ruzna "DEBUG-mode zavisla" makra.
Co se "chybeni C++" tyce,  GObject (teoreticky) poskytuje dokonce i vic "objektovych" vlastnosti nez C++, ovsem za cenu neuveritelneho mnozstvi dosti oskliveho "boiler-plate" kodu. Vetsinu "vysokourovnovejsich" objektu tedy resime tak, ze je napiseme ve Vale (mozna si nekdo vzpomene ze jsem zde pred par dny pred valou varoval), ta je "zkompiluje" do C a pak pokracujeme dale upravami vygenerovanych souboru.
Pokud neni nutne pouzivat nejake "objektove" vlastnosti (napr.dedicnost) a staci neco jako "zapouzdreny objekt", pouzivame konstrukci s "opaque" struct, tj. v .h souboru je definovany jen "typedef struct SomeObject_ SomeObject;" a funkce pracujici s "SomeObject" - tim mame vzdy dvojici ".h" a ".c" souboru fungujicich jako urcita "zapouzdrena jednotka". To je asi hlavni bod "prechodu na C" a zaroven vyreseni problemu neexistence "namespace" v C - vetsina "discipliny" je o tom dodrzet urcita pravidla pro jmena funkci a nektere "povinne" funkce/makra (new, delete, cast, asserty)
Tj. pouzivame vedle sebe jak GObject objekty (odlisene prefixem) i "dumb" objekty (viz vyse). Rekl bych ze GObject objektu mame tak 5% a postupne je eliminujeme ("vyssi" funkcnost se presouva do pythonu a plsql).
GOTO pouzivame velmi silne, ovsem z 99% pouze pri osetrovani chyb pri "komplikovanejsi" konstrukci objektu k zaruceni pouze jednoho return-u a/nebo k zajisteni korektniho "uklidu" pri chybe v konstrukci objektu. Takze se da rict, ze v ramci jedne funkce GOTO do urcite miry supluje vyjimky.
Jinak na to co by mely byt vyjimky pouzivame GError.
Atd, atd.
Co se zkusenosti tyce - nejvetsi plus je spolehlivost - za posledni 3 roky jsme meli pouze jeden "zahadny bug", ktery se navic nakonec ukazal jako spatne nastaveni objektu z externi knihovny. Obecne muzu rici, ze debugovani Cckoveho kodu, i kdyz je ho vice, je mnohem snazsi, diky tomu, ze C-cko je primitivnejsi, tak je i vetsina chyb "jednodussich" - paradoxne jsme jeste nemeli memory leak nebo segfault v produkci - coz s C++ bylo celkem caste. Ja osobne to pricitam efektu, ktery jsem mockrat v ruznych variantach cetl na ruznych mistech - protoze debugovani je slozitejsi nez psani kodu, tak kdyz napisu kod tak chytry jak to jen dokazu, tak ho pak nedokazu debugovat.
Navic code-review je opet mnohem jednodussi, protoze neni nutne zjistovat zadne vnorene vyjimky, zadne pretizene operatory, a hlavne, kdo nekdy videl jak vypada hlaseni chyby kompilatoru z nekolikrat "zanoreneho" templatu, tak oceni ze temer kazda chyba je celkem zjevna.
Nekteri lide vyzdvihovali jako prednost veci jako: stabilni ABI (u C++ to je trochu horsi), dostupnost C kompilatoru pro snad kazdou existujici platformu (vcetne embedded) - coz myslim uz dnes neni moc pravda (a mozna to nebyla pravda ani v 2008).
Rychlost kompilace rozhodne JE plus - kompilace celeho C kodu je na mem notebooku pod 30 sekund - tehdejsi C++ varianta se kompilovala i pres 10 minut (ano, mel jsem pomalejsi pocitac) - ovsem diky modularite projektu to neni az takove plus jak by se mohlo zdat.

Abych jen nechvalil - jak jiz jsem zminil, hlavni nevyhodou je delsi kod a slozitejsi testovani (mame vicemene 99% kodu pokryto unittesty), kde je nutne pouzit trochu jine principy (klasicke mockobjekty definujici nejaky interface jdou s GObject pouzit, ale je to vesmes vice prace nez se vyplati). Rozhodne je nevyhoda i to, ze kazdeho noveho programatora je nutne "prevychovat", protoze kdyz nekdo napise v CV, ze "umi C", mysli tim v 99% ze umi C++ a tedy ze vlastne umi i C.

Zajimave videt, jak se "high availability" da pojmout ruzne. U nas to znamena nasledujici:
- Zadna dynamicka alokace pameti. Nikdy.
- Procesy bezi, pusteny od startu/restartu RT schedulerem. Nevolaji se, pouze si predavaji data.
- Procesy jsou casove i pametove izolovane: kazdy bezi jen kdyz mu scheduler vyhradi okno a ma pristup pouze do sve pameti (jo, SHM se pouziva, ale explicitne pouze pro predavani nekterych informaci)
- Veskere myslitelne stavy systemu = normalni beh. Tedy kdyz neco nefunguje, jedna se pouze a jen o prechod na jiny stav stavove masiny, ktery se podle toho chova. Z toho jaksi automaticky vyplyva, ze zadne vyjimky. Pokud potrebuju vyjimku, tak to znamena, ze jsem nejaky stav neosetril explicitne. Stejnym zpusobem se resi i teoreticky bit-flip v registrech (prastil do nej neutron) - proces se muze pokazit --> scheduler ho restartuje, vysledek se nevezme v potaz diky redundanci.
- Implementace tech fakt kritickych veci je redundantni na ruznych architekturach, pomoci jinych nastroju a implementuji to ruzne firmy dle stejnych specifikaci --> uvnitr to jede komplet jinak, ale vysledky musi byt konzistentni. Kontrolu konzistence provadi nasledny konzument vysledku (dalsi krabice v retezu), vetsinou pomoci primitivni diskretni logiky.
- Stejne to vsechno ma dalsi zalohy, i kdyby tento cely retezec selhal.

A k tem vyjimkam v destruktoru: kdyz pisete kod pro sebe, delejte si co chcete.
Pokud chcete, aby ten kod pouzil jeste nekdo jiny, tak jen popisem, jak to vlastne funguje a dokazovanim a vysvetlovanim proc, stravite vice casu, nez to napsat jinak :) Nehlede na to, ze za 5 let ten kod bude chtit nekdo pouzit v jinem kontextu, a on fungovat nebude. Proc? To uz ten clovek nedohleda a radsi si napise vsechno znova.

Sten

Re:C++ a výjimka v destruktoru
« Odpověď #161 kdy: 11. 02. 2014, 12:25:17 »
~Transaction zavolá rollback. Nejspíš pouze v případě, že poslední metoda nebyl úspěšný commit. Může házet třeba, pokud vypadne spojení s databází (jak mi tady O.N. před časem napsal). Rozumné databáze v takovém případě udělají rollback samy. Takže destruktor vlastně udělal přesně to, co měl, ale stejně vyletí výjimka. Já bych tu chybu teda hlásil až ve chvíli, kdy by uživatel té knihovny to spojení chtěl použít znova. Pokud nechce, tak vypadlé spojení ničemu nevadí.

Já při této situaci házel, pokud nebyla transakce explicitně commitnuta nebo rollbacknuta a destruktor se nevolal při stack unwindu (kdy se dělal implicitní rollback), protože ten kód byl evidentně vadný. Ale samozřejmě záleží, jakým způsobem se s tím (ne)má aplikace vyrovnávat, já mívám u serverů podmínku, že assert během requestu nesmí opustit handler requestu (takže místo abortu vyhazuje výjimku, jako to dělá Java).

Re:C++ a výjimka v destruktoru
« Odpověď #162 kdy: 11. 02. 2014, 21:36:22 »
Ještě bych uvedl jednu dobrou věc na výjimkách obecně. Od té doby, co je používám jako výhradní způsob hlídání chyb mi odpadla jakákoliv práce s vytvářením systémů chybových kódů. Výjimka je samo popisná. Moje výjimky dokonce (povinně) musí hlásít i místo vzniku (__FILE__ a __LINE__) - naštěstí na to mám makro.

Kód: [Vybrat]
throw FileNotFoundException(THISLOCATION, filename);(ano, je to to makro THISLOCATION, které inicializuje objekt ProgramLocation)

- nevěřili byste jak je to užitečné. Na serverech je to užitečné vždycky, protože když se něco stane, v logu je to většinou dost popsané. Ale já to používám i na desktopových aplikacích. Každá aplikace generuje nějaký log. Někdy je ten log ukládaný jen do paměti, jindy i na disku. Pokud aplikace začne zlobit a uživatel bombarduje helpdesk svými dotazy a stížnostmi, helpdesku zpravidla stačí zaslat log. No a buď sám helpdesk z logu pozná, o co jde (jedná se třeba o částý problém), nebo to poznám později já.

Všimněte si další vlastnost
. Já s výjimkou ukládám i jméno souboru, které se nepodařilo otevřít. Tohle je prakticky nemožné zařídit systémem návratových hodnot. Pak vám aplikace nahládí "něco selhalo" nebo "soubor se nepodařilo otevřít" nebo "file not found" a nebo vám vrátí exit code 2. A teď hledejte, co se nezdařilo.

Další vlastností je výjimková hierarchie. Vytváření kategoríí výjimek. Mám základní sadu výjimek které dědí Exception. Pak výjimky ze skupiny SystemException nebo NetworkException. Threadové výjimky jsou zpravidla pod ThreadException. Souborové výjimky jsou pod IOException.

Samozřejmě mě v tom inspirovala Java (jako většina věcí)

Protože kategorie mají povinnost dědit virtuálně Exception, je povoleno dědit z vícero kategorii.

Kód: [Vybrat]
class MujProblemSeSiti: public SystemException, public NetworkException {
...
};
Já si pak na místě, kde to potřebuju mohu vybrat zda napíšu

Kód: [Vybrat]
catch(MujProblemSeSiti &e)

catch(NetworkException &e)

catch(SystemException &e)

Kód: [Vybrat]
catch(FileNotFoundException &e)

catch (IOException &e)
nebo když nevím

Kód: [Vybrat]
catch (Exception &e)
a nebo velimi obecné (odchytne drtivou většinu výjímek)

Kód: [Vybrat]
catch (std::exception &e)
handler na základní úrovni  by měl být schopen odchytnout i jinak nerozpoznanou výjimku (které ale nesmí v mých programech nikdo házet, pouze ve speciálních případech, pokud je cílem, aby výjimka nebyla odchytnuta a zahozena)

Kód: [Vybrat]
catch (...)
Jak tady někdo psal, že to sklouzává k  tomu, že výjimky se nechávají propadnout až na základní úroveň, místo aby je někdo zpracoval, tak to teda není pravda. Zpravidla na tom rozhodujícím místě dochází k větvení

Kód: [Vybrat]
catch(Vyjimka1 &e) { reportError(333, e);}
catch(Vyjimka2 &e) {reportError(666, e);}
catch(ObecnejsiVyjimka &e) {reportError(500, e);}
catch(std::exception &e) {reportGeneralError(e.what());}

Pokud někomu vadí, že musí generovat hromadu catch handlerů na konci obsluhy každého handleru, tak nemusí, dá se to udělat takto:

Kód: [Vybrat]
void processErrors() {
try {
  throw;
} catch (A a) {
...
} catch (B a) {
...
} catch (C a) {
...
} catch (D a) {
...
}
}

void handler () {
try {
....
} catch (...) {
 processErrors();
}
}

Zpět na začátek. Hlavně jsem se zbavil definování tisíců chybových kódů a hlídání toho, zda někde nekolidují. Každá knihovna měla vlastní kódy. Díky výjimkám je každá chyba přesně specifikována a zařazena do kategorie. Uvnitř aplikace létají výjimky a na vnějším rozhraní... pokud si to zadavatel přeje ... mám každé výjimkové třídě přidělen nějaký unikátní kód. A protože se to zpravidla řeší na jednom místě, není problém udržet ten seznam kódů bez kolizí.

Re:C++ a výjimka v destruktoru
« Odpověď #163 kdy: 11. 02. 2014, 21:45:33 »
Zajimave videt, jak se "high availability" da pojmout ruzne. U nas to znamena nasledujici:
- Zadna dynamicka alokace pameti. Nikdy.

To asi porovnáváme neporovnatelné. Věřte mi nebo ne, ale moje knihovny v současném návrhu (i s výjimkami) se například vůbec nedají použít v Arduinu. A to ani kdybych ty výjimky nějak vyházel. Prostě tam se programuje naprosto jinak a jen díky tomu, že to nedělám denně, nemám na to vytvořené žádné kopyto (konečně o kopytech to celé je, záleží kde a co šijete)

Re:C++ a výjimka v destruktoru
« Odpověď #164 kdy: 11. 02. 2014, 21:49:51 »
to ze se na poolove operaci nebude provadet zadne dynamicke new/delete beru za samozrejmost, k tomu vetsinou slouzi ty ruzne pametove ci kontextove pooly:-)
ono je taky fajn,pokud chces at nejaky program bezi dele nez tyden, tak se celkove vyvarovat jakyhkoli dynamickych alokaci,pokud je to principialne mozne....

To mě fakt netrápí. Server má 4GB paměti, aplikace zabírá s bídou 100MB (RES). Pokud už padá, tak kvůli něčemu jinému, než kvůli paměti.

(jo mám tam watchdog, který ho rychle nahodí zpět, takže 99.9999999% uživatelů to nepozná, takže nám to jen kazí statistiky).