Frage von JamesOffice, 51

Warum ist die Reihenfolge in dieser Funktion falsch?

Hallo, Ich steht grad aufm Schlauch... Das Folgende Programm enthält catch Blöck, die in die richtige Reihenfolge sortiert werden müssen... Könnte mir bitte jemand das erklären, und warum diese Reihenfolge falsch ist? Danke im voruas....

include <exception>

include <String>

include <iostream>

using namespace std;
class My_Exception :
public exception {};
class something {};
void func1() { throw exception(" no t h ing "); }
void func2() { throw string(" 12345 "); }
void func3() { throw out_of_range(" abcde "); }
void func4() { throw ios::failure(" i o s "); }
void func5() { throw My_Exception(); }
void func6() { throw something(); }
void func7() { throw logic_error(" t r u e "); }
int main() {
try {

 func1(); func2(); func3(); func4(); func5(); func6(); func7();

 }
catch (My_Exception) {/1/ }
catch (exception) {/2/ }
catch (logic_error) {/3/ }
catch (string) {/4/ }
catch (...) {/5/ }
catch (out_of_range) {/6/ }
catch (ios::failure) {/7/ }
catch (something) {/8/ }
return 0; 

}

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von TeeTier, Community-Experte für programmieren, 15

Dabei hilft dir diese Seite:

http://www.cplusplus.com/reference/exception/exception/

Demnach ist die Reihenfolge also:

try { /* ... */ }
catch (something) { /* 8 */ }
catch (My_Exception) { /* 1 */ }
catch (out_of_range) { /* 6 */ }
catch (logic_error) { /* 3 */ }
catch (ios::failure) { /* 7 */ }
catch (exception) { /* 2 */ }
catch (string) { /* 4 */ }
catch (...) { /* 5 */ }

Dir muss aber klar sein, dass es mehrere mögliche richtige Lösungen gibt (sogar eine ganze Menge), und die exakte Reihenfolge ist (falls überhaupt) von den Projekt-Richtlinien oder z. B. dem Bauchgefühl deines Lehrers vorgegeben. :)

Im Anhang dieser Antwort findest du noch mal den C++ Exception Tree als Grafik. :)

Den Exceptions sieht man die Vererbungshierarchie leider nicht an, aber völlig unbekannte (something) sollten oben stehen, und die Ellipse (die drei Punkte) sollte ganz am Ende stehen.

Bei allem anderen musst du die Vererbungshierarchie beachten, und um auf Nummer Sicher zu gehen, sollten bekannte Nicht-Exception Typen (string) ebenfalls direkt vor der Ellipse stehen.

Für PODs gelten die selben Regeln, wie für Klassen, also beachte auch hier die Hierarchie.

Die Position von primitiven Datentypen ist eigentlich egal, da von denen nicht geerbt werden kann, aber hierbei solltes du zwischen signed und unsigned Werten unterscheiden!

Des weiteren wird zwischen const, Zeigern, Referenzen und deren Kombinationen ebenfalls unterschieden. Hier gelten die üblichen Regeln.

Da aber in deinem Beispiel weder PODs, noch Zeiger oder ähnliches auftauchen, ist das vermutlich nicht relevant für dich, und du kannst die letzten paar Absätze meiner Antwort ignorieren. :)

Viel Spaß! :)

Antwort
von spaghetticode, 17

Dein zweiter catch ist der allgemeinste - der fängt jede Exception. Das bedeutet, egal, was geworfen wird, spätestens beim zweiten catch ist Schluss.

Beim Anordnen der catch-Blöcke fängt man bei der spezifischsten Exception an und arbeitet sich zur allgemeinsten hoch.

Stell dir eine Sortieranlage für Kleidung vor. Auf einem Fließband läuft Kleidung an fünf Arbeitern vorbei.

Arbeiter 1 soll alle roten T-Shirts aussortieren, Arbeiter 2 alle T-Shirts, Arbeiter 3 alle Baumwoll-Oberbekleidung, Arbeiter 4 alle Oberbekleidung und Arbeiter 5 alle Kleidungsstücke. Wenn du jetzt Arbeiter 5 an die zweite Position stellst, fängt der alles ab, was kein rotes T-Shirt ist. Ein blaues T-Shirt zum Beispiel ist zwar ein T-Shirt, aber eben zweifellos ein Kleidungsstück. Arbeiter 5 wird es also gemäß seines Auftrages aussortieren, bei Arbeiter 2 (der alle T-Shirts aussortieren soll) kommt es gar nicht mehr an.

Prinzip verstanden?

Antwort
von Suboptimierer, 33

Deinen Code kann man überhaupt nicht lesen.

mit try{} klammerst du Anweisungen, bei den beim Auftreten einer Schutzverletzung in den catch-Zweig gesprungen werden soll. Mit throw löst du eine Schutzverletzung willkürlich aus.

Kommentar von JamesOffice ,

#include <exception> #include <String> #include <iostram> using namespace std; class My_Exception : public exception {}; class something {}; void func1() { throw exception(" no t h ing ")}void func2() { throw string(" 12345 "); } void func3() { throw out_of_range(" abcde "); }void func4() { throw ios::failure(" i o s "); }void func5() { throw My_Exception(); } void func6() { throw something(); } void func7() { throw logic_error(" t r u e "); } int main() { try { func1(); func2(); func3(); func4(); func5(); func6();func7(); } catch (My_Exception) {/*1*/ } catch (exception) {/*2*/ } catch (logic_error) {/*3*/ } catch (string) {/*4*/ } catch (...) {/*5*/ } catch (out_of_range) {/*6*/ } catch (ios::failure) {/*7*/ } catch (something) {/*8*/ } return 0; }
Kommentar von JamesOffice ,

Danke für die Erklärung, hier ist noch mal das code... ich weiß aber gar nicht warum die Reihenfolge falsch ist... Könnten Sie mir das bitte mal erklären ? danke sehr...

Kommentar von Suboptimierer ,

Ist das eine Informatik-Aufgabe? Wahrscheinlich sollst du die Funktionen den passenden catchs zuordnen.

Beispiel: func2 → catch(string){/*4*/}, also 2 → 4

Wenn du das Programm debugst, solltest du sehen, in welchen catch er springt.

Syntaktisch fällt mir nichts auf. Ich hatte mit C allerdings bislang nur periphär zutun.

Kommentar von Suboptimierer ,

Vielleicht sollte man noch bedenken, dass nach dem catch meiner Erinnerung nach nicht wieder zurück gesprungen wird. Du müsstest also jeden Funktionsaufruf mit try-catch umklammern.

Aber wie gesagt siehst du so etwas automatisch beim Debuggen.

Antwort
von PWolff, 14

Es gibt bei Catch-Blöcken im allgemeinen nicht "die" richtige Reihenfolge, sondern mehrere sinnvolle und mehrere sinnlose Reihenfolgen.

Wenn Klasse exceptionB von Klasse exceptionA erbt

class exceptionB: exceptionA {};

dann hat es keinen Sinn, erst exceptionA und danach exceptionB abzufangen, da ja jede exceptionB auch eine exceptionA ist und schon im vorigen Block abgefangen wird.

// sinnlose Reihenfolge:
catch (exceptionA) {/* code */} // hier werden auch exceptionB abgefangen
catch (exceptionB) {/* code */} // dieser Code wird nie ausgeführt
// sinnvolle Reihenfolge:
catch (exceptionB) {/* code */} // dieser Code wird bei einer exceptionB ausgeführt
catch (exceptionA) {/* code */} // dieser Code wird bei einer exceptionA ausgeführt, die keine exceptionB ist

du müsstest also untersuchen, welche der abgefangenen Klassen jeweils von welcher anderen erbt und die catch-Blöcke so sortieren, dass immer die weiter abgeleitete Klasse vor der weniger weit abgeleiteten steht.

Bei Klassen, von denen keine in der "Ahnentafel" der anderen steht, ist die Reihenfolge egal, die können sich ja nicht ins Gehege kommen.

(Statt Klassen sind auch Interfaces möglich oder allgemein alles, als was eine abgeleitete Klasse aufgefasst wird.)

Aber ohne die Stammbäume der Vererbungen und Implementierungen der abgefangenen Klassen könnte ich nicht sagen, was dort falsch ist.

Keine passende Antwort gefunden?

Fragen Sie die Community

Weitere Fragen mit Antworten