Merkwürdige "Exception-Ausgabe"



  • Ich experimentiere ein bisschen mit den Exceptions von c++.

    Statt die Fehlermeldung anzuzeigen, die ich eigentlich wollte, stürzt das Programm ab und in der Konsole erscheint:

    "
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application's support team for more information."

    Kommt das jemandem bekannt vor? Was habe ich wahrscheinlich falsch gemacht?

    Wenn ich die Zeile mit "throw" auskommentiere, wird das Programm normal beendet.

    TiXmlDocument doc(pfad);
    	doc.LoadFile();
    	if (doc.Error()) {
    		std::string pfadstr(pfad);
    		std::cout << "error" <<std::endl;
    		throw std::logic_error("Menue-Datei \""+pfadstr+"\" konnte nicht geoeffnet werden.");
    	} else {
    		TiXmlElement* root = doc.RootElement();
    		// TODO ...
    	}
    

    Ich benutze Eclipse mit MinGW.



  • Hast du das throw in einen try-Block eingeschlossen?



  • Ich hab das throw nicht direkt in einem try-Block.
    Stattdessen ist die Stelle, wo der Konstruktor aufgerufen wird in einem Try-Block.

    Nochmal die komplette Funktion:

    Menue::Menue() throw() {
    	TiXmlDocument doc(pfad);
    	doc.LoadFile();
    	if (doc.Error()) {
    		std::string pfadstr(pfad);
    		std::cout << "error" <<std::endl;
    		throw std::logic_error("Menue-Datei \""+pfadstr+"\" konnte nicht geoeffnet werden.");
    	} else {
    		TiXmlElement* root = doc.RootElement();
    		// TODO ...
    	}
    }
    

    "pfad" ist ein static char*

    Wenn ich das try weglasse, passiert das selbe.

    Noch was:
    Der Konstruktor wird nicht direkt aufgerufen, eigentlich wird eine Funktion aufgerufen, die ihrerseits eine Funktion, die in einem Funktionszeiger gespeichert ist aufruft, die eine Instanz von "Menue" zurückgibt. 🙄
    (Ich wollte eine Art erweiterbaren Automat machen.)
    Immerhin funktioniert es ja ohne das throw.

    Brauch ich in den ganzen "Kapselfunktionen" auch throw()? Und wenn ja, brauch ich auch throw() in den Basisklassen?



  • Du verletzt absichtlich Deine "exception specification" (s.a. google).

    obbba schrieb:

    ...

    Menue::Menue() throw() { // <- hier sagst Du, dass diese Funktion keine Exception werfen soll
    ...
    throw std::logic_error(" // <- hier tust Du's trotzdem...
    

    Da solche Vergehen in C++ (wenn überhaupt) erst zur Laufzeit ausgewertet werden, siehst Du das Verhalten, das auch zu erwarten war (die runtime ruft die Funktion unexpected() auf, die standardmäßig die Funktion terminate() aufruft)

    ergo: Hat gar nichts mit try/catch zu tun.
    Lösung: Entweder auf das 1. oder auf das 2. throw verzichten
    ... und bitte das nächste Mal C++-Tags verwenden.

    Gruß,

    Simon2.



  • ahhhhh

    "throw()" bedeutet, dass alle exceptions, die ankommen "weitergeworfen" werden?

    Auf jeden Fall funktionierts jetzt. 👍



  • obbba schrieb:

    ahhhhh

    "throw()" bedeutet, dass alle exceptions, die ankommen "weitergeworfen" werden?
    ...

    😕
    Ich weiß nicht, woraus Du das jetzt schließt, aber throw hat (wie fast alles in C++) seine eigene Bedeutung, je nachdem, wo es steht:

    void f() throw(std::exception) { //1.: f darf nur std::exceptions werfen (also auch "Nachkommen)
       try {
          dosomething();
          throw std::runtime_error("schmeiß was"); // 2. wirf eine neue runtime_error-exception
       }
       catch(...) {
          cout << "error\n";
          throw; // 3. Wirf weiter, was auch immer geflogen ist
       }
    }
    

    Ein Spezialfall von 1. ist, dass throws Argumentliste leer ist ("throw()"), was gleichbedeutend ist mit "darf gar nichts werfen".

    Gruß,

    Simon2.



  • obbba schrieb:

    ahhhhh

    "throw()" bedeutet, dass alle exceptions, die ankommen "weitergeworfen" werden?

    Nein. Throw() im Funktionskopf bedeutet "diese Funktion wirft keine Exception, das darfst du zur Laufzeit gerne nachprüfen" - oder ums genau zu nehmen "aus dieser Funktion wird nie eine Exception kommen", also dürfen auch darin aufgerufene weitere Funktionen keine Exceptions werfen (es sei denn sie stehen in einem try-Block und du verarbeitest diese weiteren Exceptions).
    Anders als in Java wird das aber nicht zur Compilezeit geprüft, ob da möglicherweise doch eine Exception entfleuchen könnte, deshalb hat dein Beispiel oben auch kompiliert.
    Du hast allerdings mutwillig gegen deine eigene Exception-Spezifikation verstoßen, und das mag das Programm garnicht: wenn eine Funktion mit Exceptionspezifikation aufgerufen wird, wird jede Exception die fliegt überprüft. Ist sie nicht in der Liste der "erlaubten" Exceptions (bei dir war diese Liste leer), dann wird die Funktion unexpected() aufgerufen. Was die macht ist Einstellugnssache, wenn nichts eingestellt worden ist (via set_unexpected()) wird terminate() aufgerufen. Was terminate() macht ist auch Einstellungssache (via set_terminate()) - aber wie der Name schon sagt beendet Terminate das Programm, standardmäßig wird abort() aufgerufen, wodurch das Programm sofort beendet wird.


Anmelden zum Antworten