C++ a výjimka v destruktoru

Re:C++ a výjimka v destruktoru
« Odpověď #135 kdy: 08. 02. 2014, 10:51:33 »

Intel C++ Compiler delete nezavolá, stejně tak (zdá se) Visual Studio 2010. Kde to ale funguje je clang++.

Potvrzuju, clang-3.3 (Ubuntu 12.04 LTS) funguje jak má

 
Kód: [Vybrat]
ondra@cornelie:/tmp$ clang++ raw.cpp
ondra@cornelie:/tmp$ ./a.out
create
new
destroy
destruct
delete
exception 1
ondra@cornelie:/tmp$

Mimochodem, o existenci clangu jsem doposud nic nevěděl. Jdu ho vyzkoušet.


RAII

Re:C++ a výjimka v destruktoru
« Odpověď #136 kdy: 08. 02. 2014, 13:02:13 »
To Ondřej Novák: hele, jak si moh používat tu svoji knihovnu která hází exceptions v destruktorech když žádný kompiler (GCC,Intel C++ a VS) tuto schopnost naprosto správně neimplementuje?
Clang prej fachčí, ale o něm si zase nevěděl. No vysvětli mi prosím ten chaos...

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #137 kdy: 08. 02. 2014, 13:30:18 »
To Ondřej Novák: hele, jak si moh používat tu svoji knihovnu která hází exceptions v destruktorech když žádný kompiler (GCC,Intel C++ a VS) tuto schopnost naprosto správně neimplementuje?
Clang prej fachčí, ale o něm si zase nevěděl. No vysvětli mi prosím ten chaos...

Tohle není žádná záhada. Destruktory hází jen zřídka a to, že se v tom případě nezavolá delete znamená jen memory leak. Samozřejmě předpokládám rozumné operátory delete, ne žádné divočiny. Navíc bych u objektů s nějakým složitým destruktorem nečekal, že budou zabírat moc paměti, pokud vůbec buou na heapu. Velké bloky paměti budou spíš alokované zvlášť a spravované nějakým chytrým ukazatelem, který se v tomhle případě zruší správně.
Takže i s tímhle bugem program tu a tam leakne maximálně tak pár kilo. Na nasbírání problematického množství paměti bude třeba hódně času. Dřív přijde restart, nebo ten program zdechne na něco jiného.

Samozřejmě že dokážu vymyslet příklad, kdy to těžce selže. Třeba veliké pole objektů s házejícími destruktory.

Re:C++ a výjimka v destruktoru
« Odpověď #138 kdy: 08. 02. 2014, 14:30:58 »
Což o to leaky mi kontrolují různé nástroje a nikdy jsem si žádného nevšiml. Asi zpravidla proto, že většinou jde o objekty, u kterých se předpokládá, že vzniknou na zásobníku. Má oblíbená architektura totiž vypadá takto

1.  objekt co vlastní zdroj
2.  objekt co s ním manipuluje (manipulant - builder)

Ten co vlastní zdroj, ten bývá často (ale ne vždy) alokován dynamicky. Naopak builder bývá výhradně na zásobníku. Builder většinou v destruktoru uvádí zdroj do konzistentního stavu, tak aby se případně dal používat s nějakým dalším builderem. Pokud by builder nedokázal zanechat zdroj v konzistentním stavu, tak je to fatal error a právě zde se má / měla hodit výjimka. Nedokážu si představit, že by se to zaignorovalo. Případný další builder bude pracovat s nekonzistentním zdrojem... NO WAY... to je těžkej malér.

Jediný co mě napadlo, jak by se to dalo řešit je výjimku forwardovat budoucímu builderovi, který ji výhodí v konstruktoru. Znamená to ale, abych si u zdroje vedl jeho stav, nebo ještě jednodušeji, abych výjimku zachycenou v destruktoru místo vyhození uložil do objektu držící zdroj.

Ani to neřeší problém 100%. Pokud mám pool zdrojů, třeba databázových spojení a já uložím do poolu nekonzistentní zdroj (protože jsem se nedozvěděl, že je nekonzistentní, žádná výjimka nevylítla), tak i forwardovaná výjimka vylítne tomu, kdo další takový zdroj vytáhne z poolu. A ohlásí chybu  ... to může být třeba další request na serveru... chyba se ohlásí tedy někomu, kdo za to nemůže... NO WAY!

Takže mě ještě napadl další workaround. Dodělat do všech možných zdrojů, které mám, kromě funkce forwardování výjimky, taky funkci na kontrolu integrity (checkIntegrity()). Tato funkce by mohla hodit forwardovanou výjimku. Před uložením do poolu by se to zavolalo a pokud by výjimka vylítla, tak by se zdroj rovnou zlikvidoval a do poolu by se nevracel. Bohužel, vracení do poolu je realizováno v destruktoru  :D Takže onu výjimku si mohu maximálně strčit ... někam do logu.

Ještě příklad. Když mi v destruktoru transakce falíruje operace rollback, už nemám šanci se to dozvědět (a to ani v případě, že neletí žádná výjimka) a maximálně při vracení mysql spojení do poolu mohu ověřit, jestli tam není někde forwardovaná výjimka a pokud ano, tak ji zalogovat a z databáze se odpojit ... snižit počet aktivních spojení z databází, pool pak vyrobí novou konekci.

Uff a to je kvůli tomu, že mi selhal rollback

ferren

Re:C++ a výjimka v destruktoru
« Odpověď #139 kdy: 08. 02. 2014, 15:38:12 »
me tato cela debata prijde ponekud mimo. nejak jsem to tu proskakal, a v podstate jsou tu 2 tabory a oba mi prijdou ponekud mimo.
kvizova otazka, z diskutujicich podilel se nekdy nekdo na programu,ktery MUSEL neustale bezet? treba z pouheho duvodu ze minutovy vypadek znamena obrovskou ztratu penez? jsem se ve sve kariere navstivil 2 pomerne nesourode svety. jeden zalozeny ciste na vykon (hpc) a druhy naopak slow computing, ale pozadavek na nonstop beh bez jedine minuty vypadku (telco).

vyjimky jsou zlo, a co vim se nic takoveho nikde nepouziva. vetsina spolecnosti v high availability by si nic takoveho neodovolila. je treba dusledne osetrovat navratove stavy, psat vse dusledne tak aby vubec k zacdnemu stavu,ktery by se vubec dal osetrovat exceptiony ani nemohlo dojit. tady to nekolikrat omilane fopen bez toho mizerneho IFu, osetrovat tu pres vyjimku je vylozene napresdrzku. taky ne mnohdy slusnejsi napresto regulerne crashnout az na zem, ale ani se nepokusit znekonzistenit nejaka data. koneckoncu jakekoli high availability reseni pocita s behem vice instanci master/slave rizenych opet nekolikrat jistenym directorem, takze crash/restart je to mensi zlo nez hejrup osetrovani exceptionu v odflaklych kodech...
a ten zde zminovany autopilot, presne tak se to dela...autopilotu bezi vzdy paralelne vic, jsou kontrolovany zvenku. krom toho ze jsou temer jiste psane v jazycich co tyhle zparchantele exception handlingy ani neumoznuji, tak jiste je v nich daleko vetsi pruser kdyz vubec dojde ke stavu,ktery je nutne nejak osetrovat a pokud, tyhle systemy se zcela regulerne a spravne cele restartuji, protoze to je v tomto pripade jedine konzistentni reseni....


Re:C++ a výjimka v destruktoru
« Odpověď #140 kdy: 08. 02. 2014, 15:58:06 »


Tenhle příspěvek je zbytečný. Ani oddělení autopilotů na samostatné počítače a jejich restart (restart celých počítačů v době chyby) neznamená, že to vždy bude konzistentní. Už jsem viděl dost chyb založených na tom, že nějaký řídící program zanechal svěřený prostředek v nekonzistentním stavu a po restartu nebyl schopen práce. Bylo nutné jít a manuálně uvést ten prostředek do počátečního stavu, aby se řídící program chytil ... byl to nějaký souřadnicový řezací stroj ... ano, měl i standardní inicializaci, ale ono to bylo složitější.

Od té doby mám rád výjimky, protože je tu pořád slušná šance, že při chybě budou k dispozici data potřebná k nápravě. Když program spadně sigsegv, nelze o jeho stavi nic říct. Když je od někud vyhozená výjimka, jedná se o řízený pád, kde každý komponenta vzniklá během činnosti dostane informaci o tom, že se něco děje a může na to vhodně reagovat. Process je to řízený, takže není nebezpečný, naopak nebezpečné je to nechat spadnou. A neberu ani argument, že to takhle dělají nějaké přetechnizované firmy s vysokým stupněm zabezpečení. Z téhle diskuze je vidět, že výjimkám ještě hodně lidí nerozumí a tak je pro zodpovědné osoby mnohem snažší a bezpečnější spolehnout se ještě na jiné technologie.

Nehledě na oblíbený problém zakonzervovaných seniorů, kteří se těší důvěře produktových managerů a jinak mají na celý problém přesně ten názor, jaký zde prezentujete, aniž by bylo podpořen jediným argumentem


Re:C++ a výjimka v destruktoru
« Odpověď #141 kdy: 08. 02. 2014, 16:27:16 »
Opet jste nepochopil o cem mluvim. V teamu mate 10 lidi, z nich 2-3 jsou "dobri", 3 "prumerni" a zbytek jsou matlalove. To co pisete musi pochopit a dodrzovat jak ti "dobri", tak "matlalove". O tom mluvim.
Rad bych ignoroval Vase narazky na moji schopnost/neschopnost, protoze to nema nic spolecneho s tim o cem mluvim, ale nejsem 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. Muzete mi samozrejme neverit, a myslet si, ze je mi 70 a rozciluje me ta dnesni mladez co pise same templaty a objekty, kterym jako geront nerozumim, misto aby pekne vyfiknuli pointerovou aritmetiku, na ktere baziruji protoze to je jedine co umim. Pripadne Vam nabizim jeste alternativu, ze je mi 13 let a kompletne blabolim, protoze umim pouze VisualBasic, nicmene jsem kdesi cetl, ze "v cecku" delaji profici a tak machruji.

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.

ferren

Re:C++ a výjimka v destruktoru
« Odpověď #142 kdy: 08. 02. 2014, 16:29:02 »
co si predstavujete pod tim ze "zachoval prostredek v nekonzistentnim stavu" ?  napr ulozena data? ty jsou nekonzistentni z 2 duvodu 1) chyba v algoritmu co data generuje b) selhani zapisu jako takoveho( vetsinou hw problem) . tohle je mozne, ale to je zcela mimo sferu toho zda exceptiony ano/ne protoze ani jeden problem tohle neresi.
exceptiony vedou k lajdackemu psani kodu, aneb proc osetrovat kazdou prkotinu kdyz to muzem vzit po blocich....zavadeji sposutu moznosti jak si usnadnit zivot a nepremyslet o tom co proc takto pisu. (samozrejme to nevypliva z zavedeni exc handlingu jako takoveho, ale je to logicky dusledek pro prirozene line lidi)

btw mozna i casove by bylo jednodusi napsat lepe ten ohandlovany kod nez se drbat pravou rukou na .... a rozjimat o vyjimkach v destruktorech na akademicke urovni....


ferren

Re:C++ a výjimka v destruktoru
« Odpověď #143 kdy: 08. 02. 2014, 16:45:30 »
majo33:
prechod z c++ na c je mozna az ponekud extremni reseni,ale neni problem psat kod v c++ 11 a presto aby to na pohled vypadalo pomejne "cckoidne" a dalo se takovy kod nejen rychle psat, ale i cist (coz je to co c++ neustale ztraci a dohani z pohledu citelnosti i takove proslavene bastlu jako perl ;-)

Re:C++ a výjimka v destruktoru
« Odpověď #144 kdy: 08. 02. 2014, 17:35:58 »
btw mozna i casove by bylo jednodusi napsat lepe ten ohandlovany kod nez se drbat pravou rukou na .... a rozjimat o vyjimkach v destruktorech na akademicke urovni....

Vůbec netušíš o čem mluvíš. Kód, který tady řeším vypadá takto:

Kód: [Vybrat]
{
Connection conn = mysqlpool.get();
Transaction trn(conn);
Result res = trn.SELECT("*").FROM(...).....;
....
trn.commit();
}

Z každého příkazu může vylítnou výjimka.
Z mysqlpool.get() například když dojdou spojení v poolu a vyprší timeout
Z transaction v okamžiku, kdy databáze odmítne příkaz BEGIN
Z sql příkazu může vylítnout cokoliv, třeba když napíšu ten dotaz blbě, nebo když databáze mezitím spadne
Z commitu může vypadnout taky víceméně cokoliv, pokud to databáze odmítne commitonouy

Víceméně všechny výjimky odchytává rpc server, ihned po návratu z handleru a vrací na to chybu 500. Zároveň do logu zapisuje chybovou hlášku, která vylítla s výjimkou.

Dám ti úkol. Napiš to bez výjimek. A zkus to navrhnout tak, aby se takový kód dal použít třeba 234x (zhruba tolik metod má můj server na svém RPC rozhraní) - poznámka pro rejpaly, ono to tělo není vždy úplně stejné a některé metody tedy databázi nepotřebují, ale moc jich není.

Ta akademická diskuze je jen o tom, jestli mají létat výjimky z té časti mezi posledním příkazem a složenou závorkou (třeba při rollbacku transakce, nebo chyba při vracení spojení do poolu.

ferren

Re:C++ a výjimka v destruktoru
« Odpověď #145 kdy: 08. 02. 2014, 18:40:57 »
ad ten priklad, db nejsou vubec ma parketa, takze kdyz koukam jen na ty radky aniz bych vedel co uvnitr delaji tak strelba od boku...

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...

2) Transaction trn(conn);
kdyz odmyslime trivialni variantu na if(conn.valid()) ktera dela obrovsky ifovy overhead kolem tak se to da rozumne poresit uvnitr toho konstruktoru aby na nevadilni connection vznikla reguleni nevalidni transaction co na jakykoli nasledujici command jako...
Result res = trn.SELECT("*").FROM(...).....;
proste nic taky neudela, to plati i na ten nasledujici commit()

kdyz to bude reseno uvnitr,navenek ten kod muze byt uplne identicky jak ten tvuj, zadny if-ovy balast kolem a presto nemusi nikdy generovat vyjimky. konkretni realizace je spis zavisla na cetnosti/pravdepodobnosti nevalidnich stavu z hlediska performance....


Jakub Galgonek

Re:C++ a výjimka v destruktoru
« Odpověď #146 kdy: 08. 02. 2014, 20:46:42 »
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).

Re:C++ a výjimka v destruktoru
« Odpověď #147 kdy: 08. 02. 2014, 22:12:03 »
2) Transaction trn(conn);
kdyz odmyslime trivialni variantu na if(conn.valid()) ktera dela obrovsky ifovy overhead kolem tak se to da rozumne poresit uvnitr toho konstruktoru aby na nevadilni connection vznikla reguleni nevalidni transaction co na jakykoli nasledujici command jako...
Result res = trn.SELECT("*").FROM(...).....;
proste nic taky neudela, to plati i na ten nasledujici commit()

kdyz to bude reseno uvnitr,navenek ten kod muze byt uplne identicky jak ten tvuj, zadny if-ovy balast kolem a presto nemusi nikdy generovat vyjimky. konkretni realizace je spis zavisla na cetnosti/pravdepodobnosti nevalidnich stavu z hlediska performance....
Tohle snad není myšleno vážně, že ne. A co ten selekt jako vrátí za data, když bude ta transakce nevalidní? Prázdnou tabulku? Co když tam bude SELECT NOW(); který evidentně prázdnou tabulku nemůže vrátit. Co když tam bude nějaký super extra dlouhý a komplikovaný výpočet, který navíc bude záviset na datech v té databázi, takže při prázdných tabulkách bude trvat neuvěřitelně dlouho, nebo se dostane do nekonečné smyčky? Třeba proto, že to mělo něco do databáze zapsat a následně vyzvednout něco jiného, co tam nebude, takže se to bude do nekonečna opakovat? Člověče, že vás tady vůbec školím. Doporučuju se od programování držet v uctihodné vzdálenosti, a zabývat se třeba ... já nevím, tvorbou webovek v PHPku....

To jsem ještě neviděl! Jo studenti v prvním ročníku mají takové děsivé nápady.

Re:C++ a výjimka v destruktoru
« Odpověď #148 kdy: 08. 02. 2014, 22:15:26 »
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).

On je tam vlastně ukazatel na mysql connection a destruktor, co vypůjčenou konekci vrací do nějakého kontejneru a samozřejmě ukazatel mysqlpool, aby to vědělo, kam to má vrátit. Samo se předpokládá, že v době destrukce ten mysqlpool bude ještě existovat, ale chyby tohoto druhu se stávají výjimečně.

ferren

Re:C++ a výjimka v destruktoru
« Odpověď #149 kdy: 08. 02. 2014, 22:24:00 »

Tohle snad není myšleno vážně, že ne. A co ten selekt jako vrátí za data, když bude ta transakce nevalidní? Prázdnou tabulku? Co když tam bude SELECT NOW(); který evidentně prázdnou tabulku nemůže vrátit. Co když tam bude nějaký super extra dlouhý a komplikovaný výpočet, který navíc bude záviset na datech v té databázi, takže při prázdných tabulkách bude trvat neuvěřitelně dlouho, nebo se dostane do nekonečné smyčky? Třeba proto, že to mělo něco do databáze zapsat a následně vyzvednout něco jiného, co tam nebude, takže se to bude do nekonečna opakovat? Člověče, že vás tady vůbec školím. Doporučuju se od programování držet v uctihodné vzdálenosti, a zabývat se třeba ... já nevím, tvorbou webovek v PHPku....

To jsem ještě neviděl! Jo studenti v prvním ročníku mají takové děsivé nápady.
[/quote]


:-) bud jsi to nepochopil a nebo um,yslne ignoroval, samozrejme ze krom toho ze na neplatne transakci nebudes delat zadne operace,tak se zachovas scela korektne a zpusobne, tj krom toho ze to zajiste nekam zalogujes tak se zachovas tak abys neco nenarusil, nastavis nebo vrasis prislusnou chybu.
ale takova prkotina,ze namas prave volno v poolu, je zcela regulerni vec se kterou se jiste musi vsude pocitat a urcite si nezaslouzi obsluhu vyjimkou....je zcela normalni ze vetsina netrivialnich akci muze selhat

btw nevim koho chces ucit, nebudes nahodou nejaky doktorand/asistent?:-)