C++ a výjimka v destruktoru

Re:C++ a výjimka
« Odpověď #180 kdy: 12. 02. 2014, 21:38:53 »
Protoze ja mluvim celou dobu o osetrovani chyb pomoci errorkodu v C. VC. Chapu ze ve Vasi snaze me argumety ignorovat jste to pochopil tak, ze za cely zivot jsem se ucastnil 3 projektu vseho vsudy. PROTO jsem psal "v C".
Cela pointa toho odstavce byla ukazat Vam, ze nevite jak delat spolehlive a velke projekty v C.

Celé je to o tom, že se snažíte mne (a vlastně i sobě) dokázat, že umět čisté C je leet, je to něco co stojí za pozornost. Zatímco já si myslím, že umět jenom C je oslavovat zastaralé technologie a bát se těch nových. Takže v mých očích jste n00b i kdyby jste se naučil v C třeba silanizovat. Je to asi to samé, jako být spisovatel a vyžívat se v tom, jak umíte rychle a bezchybně psát na stroji a díky tomu se můžete řadit mezi elitu... zatímco ostatní píší dávno na počítačích a maximálně se vám vysmějou.

Tím neříkám, že by C mělo být zatraceno úplně. V určitých situacích má své opodstatnění (stejně tak jako ten mechanický psací stroj)....

(Představte si, že dokonce i jednočipy se programují v C++)

Jinak pokud Vim, iPhone pouziva ObjC, ne C.

To je sice možný, ale to jsem já nedělal, nehledě na tom, že celý projekt byl v Marmeládě, nicméně já jsem pracoval s originálními zdrojáky, které jsou v C a upravoval jsem je na konverzi (tu jsem ovšem nedělal).


Vertigo

Re:C++ a výjimka v destruktoru
« Odpověď #181 kdy: 12. 02. 2014, 22:06:18 »
To belzebub
Obdivuji vaši trpělivost.

To "zastaralé technologie"
Řešiče soustavy lineárních rovnic (MSC/Nastran, Boeing) se dodnes píší ve Fortranu...

Re:C++ a výjimka v destruktoru
« Odpověď #182 kdy: 12. 02. 2014, 22:17:01 »

To "zastaralé technologie"
Řešiče soustavy lineárních rovnic (MSC/Nastran, Boeing) se dodnes píší ve Fortranu...

opakuju:
Tím neříkám, že by C mělo být zatraceno úplně. V určitých situacích má své opodstatnění (stejně tak jako ten mechanický psací stroj)....

Konec flame.

死神

  • ***
  • 159
    • Zobrazit profil
Re:C++ a výjimka v destruktoru
« Odpověď #183 kdy: 13. 02. 2014, 10:00:41 »
To "zastaralé technologie"
Řešiče soustavy lineárních rovnic (MSC/Nastran, Boeing) se dodnes píší ve Fortranu...

V jakém Fortranu? Třeba tady jsou novinky ve Fortranu 2008. Řekl bych, že to na zastaralé technologie ani nevypadá  ;D

Pavel Tisnovsky

Re:C++ a výjimka v destruktoru
« Odpověď #184 kdy: 13. 02. 2014, 11:29:11 »

To "zastaralé technologie"
Řešiče soustavy lineárních rovnic (MSC/Nastran, Boeing) se dodnes píší ve Fortranu...

opakuju:
Tím neříkám, že by C mělo být zatraceno úplně. V určitých situacích má své opodstatnění (stejně tak jako ten mechanický psací stroj)....

Konec flame.

Přesně, C ani Fortran a (kupodivu :-) ani C++ nepatří mezi tu obrovskou skupinu programovacích jazyků, které umřely, protože nenabídly programátorům nic moc užitečného (těch jazyků už asi budou stovky, úspěšných a používaných maximálně desítky - viz Tiobe).

Já třeba chápu C a Fortran jako velmi dobré a nadčasové DSL a záleží jen na konkrétním projektu, který z těch jazyků se bude hodit víc (ideální je asi spojení dvou či tří úrovní jazyků). Navíc ANSI C je jeden z mála jazyků, u kterých si můžu být jistý, že mé skoro už 25 staré algoritmy ještě za dalších 25 let přeložím a ony pojedou :-) [něco podobného mi říkali lidi o Fortranu 77]



td

Re:C++ a výjimka v destruktoru
« Odpověď #185 kdy: 13. 02. 2014, 11:30:15 »
To belzebub
Obdivuji vaši trpělivost.

To "zastaralé technologie"
Řešiče soustavy lineárních rovnic (MSC/Nastran, Boeing) se dodnes píší ve Fortranu...

Já zase zcela souhlasím s Ondřejem Novákem, a trpělivost a úsilí které vložil do zdejší diskuze mi přijdou až nadlidské, i když se nezdá že by tu měly šanci padnout na úrodnou půdu. Pro mě jsou řetězené výjimky jednoznačně nejpraktičtější, nejpohodlnější a přitom velice bezpečný způsob, jak v imperativním jazyce ošetřovat chybné vstupy a selhání periferií, a umožnit uživatele přes řetěz výjimek informovat, co neočekávanou situaci způsobilo. V této diskuzi se nicméně zdá, že každý se drží své pravdy, má za sebou N let praxe kdy to dělal po svém, "a proto" je to tak lepší než to druhé řešení.

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #186 kdy: 13. 02. 2014, 15:38:55 »
Já zase zcela souhlasím s Ondřejem Novákem, a trpělivost a úsilí které vložil do zdejší diskuze mi přijdou až nadlidské, i když se nezdá že by tu měly šanci padnout na úrodnou půdu. Pro mě jsou řetězené výjimky jednoznačně nejpraktičtější, nejpohodlnější a přitom velice bezpečný způsob, jak v imperativním jazyce ošetřovat chybné vstupy a selhání periferií, a umožnit uživatele přes řetěz výjimek informovat, co neočekávanou situaci způsobilo. V této diskuzi se nicméně zdá, že každý se drží své pravdy, má za sebou N let praxe kdy to dělal po svém, "a proto" je to tak lepší než to druhé řešení.
Tak jednoznačně nejpohodlnější ty zřetězené výjimky opravdu jsou. Není třeba nic analyzovat, promýšlet co všechno volající může potřebovat a chtít, nic takového.

Teď co to znamená dál:

Volající musí přesně vědět, co se uvnitř děje. Pokud netuší, jaké výjimky může v tom zřetězení dostat, tak si s nima moc neporadí. Může leda tak vypsat uživateli what() a doufat že ten bude vědět, co s tím. Mimochodem, what je pro běžného uživatele programu užitečný jen hodně omezeně. Už jen lokalizovat se to dá fakt blbě. Pořádně se to dá akorát zalogovat a poslat vývojáři.

Tím, že volající musí vědět co se uvnitř děje tak efektivně padá veškerá abstrakce. V tu chvíli nejdou prakticky překopat vnitřnosti modulu, protože ty jsou skrz výjimky součástí rozhraní. Program se nedá odstínit od detailů typu "tahám to video ze souboru nebo ze sítě?". Díky těm zřetězeným výjimkám musí každá úroveň programu do které ty výjimky můžou probublat vědět, co přesně se děje níž. Pokud to neví, tak vlastně nemá cenu ty výjimky ani házet.

Re:C++ a výjimka v destruktoru
« Odpověď #187 kdy: 13. 02. 2014, 16:09:26 »
Tím, že volající musí vědět co se uvnitř děje tak efektivně padá veškerá abstrakce.
...
Díky těm zřetězeným výjimkám musí každá úroveň programu do které ty výjimky můžou probublat vědět, co přesně se děje níž. Pokud to neví, tak vlastně nemá cenu ty výjimky ani házet.

To přece není pravda. To je jen tvrzení, které funguje na principu ode zdi ke zdi. Buď mám absolutní abstrakci a nemohu použít výjimky (a to si úplně nejsem jist pravdivostí tohoto tvrzení), nebo se musím vzdát abstrakce úplně. Nic mezi tím nevidíte.

Definice výčtu výjimek patří k definici rozhraní - malá poznámka pod čarou: jako rozhraní si můžete představit plně abstraktní třídu, nebo interface v javě. Každé rozhraní by mělo mít tzv. referenční implementaci, která ukazuje, jak se co má implementovat a mělo by 100% dodržovat pravidla rozhraní. Referenční implementace samozřejmě bude házet jen výjimky z výčtu, žádné jiné. To je ta abstrakce.

Bohužel nebo bohudík, rozhraní vznikají proto, aby skryly implementační detaily, nicméně to stejně nejde, protože už v implementaci nějakého rozhraní můžeme najít výrazné odlišnosti, úlevy a zkratky. Například rozhraní IPes má metodu VrtětOcasem(), tato metoda bude u objektu Buldok prázdná (buldok praktický nemá ocas). A to je ten lepší případ (čekali byste ze metoda IStream::closeOutput způsobí odeslání HTTP requestu pokud je tam HttpStream? No ale logiku to má, i když u TCPStreamu se spíš používá k uzavření spojení - příklad z knihovny LightSpeed).

To samé je to s výjimkami. Každý objekt by měl dodržovat rozhraní i na úrovni výjimek. Ale implementace se může začít potýkat s problémem, který na rozhraní definovaný není. Strojí před problémem. Má to vyhodit jako výjimku, která není na rozhraní definovaná? Nebo to má zabalit do jiné výjimky z nějaké existující, ke které to připojí Reason?

Opět příklad. HttpStream může vyhodit HttpStatusException. Ta ale na rozhraní IStream není definovaná. Tam je definovaná výjimka IOException. (zadání)

 Má se tato výjimka vyhazovat jako IOException a jako reason vložit HttpStatusException?

Opět záleží, jak předpokládáte, že se to bude používat. Předpokládám tuto hierarchii

Kód: [Vybrat]

 + - (1) otevírám HttpStream, chci si něco stáhnout
   + - (2) čtu soubor přes IStream (třeba to je parser JSONu, který pracuje nad obecným streamem)
     + - (3) při čtení obdržím status 500 Internal Server Error

Co chci? Chci na úrovni (2) odchytit IOException? Co s tím na té urovni budu dělat? Pokud je tam JSON parser, tak asi nic, ten to hodí dál. Může to také vyřešit tak, že z toho vybalí reason a ten hodí. Jenže JSON parser nemůže vědět, zda nad ním náhodou není někdo, komu by se třeba hodilo, aby to bylo IOException

Takže asi budu chtít na úrovni (1) odchytávat HttpStatusException.

V tomto případě bych asi pro HttpStream výjimku nebalil a i když není na úrovni rozhraní IStream definovaná. Nicméně mohu předpokládá, že ten, kdo si objednal čtení přes HTTP protokol, bude nejspíš vědět, jak s výjimkou HttpStatusException naložít, spíš než s chybou IOException.


Jak já to dělám? HttpStatusException dědí IOException. Ne vždy to ale takhle jde řešit.

Jakub Galgonek

Re:C++ a výjimka v destruktoru
« Odpověď #188 kdy: 13. 02. 2014, 16:19:46 »
Tím, že volající musí vědět co se uvnitř děje tak efektivně padá veškerá abstrakce. V tu chvíli nejdou prakticky překopat vnitřnosti modulu, protože ty jsou skrz výjimky součástí rozhraní. Program se nedá odstínit od detailů typu "tahám to video ze souboru nebo ze sítě?".

Ony i chybové kódy, které může funkce vracet, jsou součástí rozhraní. Pokud překopeš vnitřnosti modulu tak, že najednou z něj budou moci lézt jiné chybové kódy, tak máš také zaděláno na problém.


Díky těm zřetězeným výjimkám musí každá úroveň programu do které ty výjimky můžou probublat vědět, co přesně se děje níž. Pokud to neví, tak vlastně nemá cenu ty výjimky ani házet.

Nemusí vědět přesně, co se děje níž. Volající ví, jaké výjimky mu můžou přijít, a volaný ví, jaké výjimky může vyhodit.

Re:C++ a výjimka v destruktoru
« Odpověď #189 kdy: 13. 02. 2014, 16:21:18 »
Volající musí přesně vědět, co se uvnitř děje. Pokud netuší, jaké výjimky může v tom zřetězení dostat, tak si s nima moc neporadí. Může leda tak vypsat uživateli what() a doufat že ten bude vědět, co s tím. Mimochodem, what je pro běžného uživatele programu užitečný jen hodně omezeně. Už jen lokalizovat se to dá fakt blbě. Pořádně se to dá akorát zalogovat a poslat vývojáři.

Běžně se to dělá tak, že se známé výjimky převedou na chybové hlášky.

Kód: [Vybrat]
void openDocument(const char *fname) {
 try {
    .....
 } catch (FileNotFoundException &e) {
      MessageBox(FormatMessage(IDS_SOUBORNEBYLNALEZEN, e.getFilename());
 } catch (AccessDeniedException &e) {
      MessageBox(FormatMessage(IDS_NEMATEPRISTUPKSOUBORU, e.getFilename());
 } catch (DocumentParseError &e) {
      MessageBox(FormatMessage(IDS_SOUBORNEBYLROZPOZNAN, e.getFilename());
 } catch (std::exeption &e) {
      LogError(e);
      MessageBox("Neznama chyba, kontaktujte vývojáře");
 }

}

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #190 kdy: 13. 02. 2014, 17:27:56 »
Aha, už začínám chápat, kde si nerozumíme. Pokud potřebuju protáhnout nejakou výjimku skrz cizí kód a na obou koncích jsou moje objekty, tak může být reason rozumné řešení. Pokud bych něco takového musel udělat já, tak bych nejspíš ten cizí kód zkusil nějak obejít než přes něj tu chybu protahovat. Např. z callbacku bych chybu dostával ven přes userdata a ne výjimkami a podobně bych postupoval u toho streamu.

Taky moduly skládám dohromady úplně jinak, holt řeším jiné problémy. Třeba se nepotkávám s tak vyžranými jsony, že bych musel parseru předhazovat stream. Json ze serveru přijmu jako string a ten string pak předám parseru. Takhle mám http komunikaci i parser jsonu vedle sebe a ne v kaskádě a nemusím chyby z jednoho modulu protahovat skrz jiný.

Re:C++ a výjimka v destruktoru
« Odpověď #191 kdy: 13. 02. 2014, 21:20:27 »
Tím, že volající musí vědět co se uvnitř děje tak efektivně padá veškerá abstrakce. V tu chvíli nejdou prakticky překopat vnitřnosti modulu, protože ty jsou skrz výjimky součástí rozhraní. Program se nedá odstínit od detailů typu "tahám to video ze souboru nebo ze sítě?". Díky těm zřetězeným výjimkám musí každá úroveň programu do které ty výjimky můžou probublat vědět, co přesně se děje níž. Pokud to neví, tak vlastně nemá cenu ty výjimky ani házet.

Ano tohle je celkem nešťastné řešení výjimek v jazycích jako C++, Java. Common Lispové řešení v podobě restartů je mnohem lepší.

Re:C++ a výjimka v destruktoru
« Odpověď #192 kdy: 14. 02. 2014, 15:24:38 »
Taková perlička pro Stena a milovníky MSVC (2010)

Kód: [Vybrat]
ParallelExecutor2::~ParallelExecutor2() try {
stopAll();
} catch (...) {
if (std::uncaught_exception()) return;
}

class ParallelExecutor2::Worker {   //error C2911: 'LightSpeed::ParallelExecutor2::Worker' : cannot be declared or defined in the current scope
public:
....
};

Ovšem po úpravě předchozího try catch bloku v destruktoru...

Kód: [Vybrat]
ParallelExecutor2::~ParallelExecutor2() { try {
stopAll();
} catch (...) {
if (!std::uncaught_exception()) throw;
} }

class ParallelExecutor2::Worker {
public:
....
};

se to přeloží bez chyby

Evidentně MSVC parser C++ rozhodí zápis s try před tělem funkce. Gcc a v Clangu se to přeloží obojí

JSH

Re:C++ a výjimka v destruktoru
« Odpověď #193 kdy: 14. 02. 2014, 21:13:29 »
Že Visual studio neumí ani tohle mě vlastně ani moc nepřekvapuje. Když porovnám to, co MS zatím jen slibuje s tím, co už GCC a clang mají, tak je to dost děsivé.

Pro ty, co C++ moc neznají doplním, že ty dva kusy kódu ani zdaleka nejsou identické. V prvním bude ten catch block chytat i výjimky, které vyhodí destruktory členských proměnných a bázových tříd toho objektu. Ve druhém případě ten blok chytne jen to, co vyhodí funkce stopAll().
Tuhle konstrukci je možné vidět i v konstruktorech, když je třeba chytit výjimku z konstruktoru bázové třídy.

Předpokládám, že
Kód: [Vybrat]
if (std::uncaught_exception()) return;
je chyba, ano? Takhle by ten catch block spolkl výjimku vždycky a ten test by tam vůbec nemusel být.

Re:C++ a výjimka v destruktoru
« Odpověď #194 kdy: 14. 02. 2014, 23:04:56 »
Předpokládám, že
Kód: [Vybrat]
if (std::uncaught_exception()) return;
je chyba, ano? Takhle by ten catch block spolkl výjimku vždycky a ten test by tam vůbec nemusel být.

Není to chyba:
http://stackoverflow.com/questions/5952837/try-catch-block-substituted-for-a-method-block-in-a-destructor

Citace
due to ISO/IEC 14882:2003 15.3 [except.handle] / 16:

    The exception being handled is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. [...]

However it is legal to have a parameterless return in the handler of a function try block for a destructor - it is only forbidden in a function try block for a constructor - and this will supress the rethrow of the exception. So either of these alternatives would prevent the exception from leaving the destructor

Opět ne všechny překladače to umí