std::runtime_error wird nicht gefangen
-
Moin,
ich steht gerade echt auf dem Schlauch: Eine Funktion zum lesen einer Datei wirft einen std::runtime_error, wenn die Datei nicht vorhanden ist. Das Problem ist, obwohl ich der Meinung bin, diesen zu fangen, aborted mein Programm mit der Meldung "terminate called after throwing an instance of 'std::runtime_error'"
Was mach ich hier falsch:
std::string loadFile(const std::string& file_name) throw (std::runtime_error) { if(datei existiert nicht) { throw std::runtime_error(file_name); } lese_den_kram_ein(); } ... Foo::Foo() { std::string config; try { config = loadFile("pfad/zu/nichtexistenter.datei"); } catch (std::runtime_error& ex) { Log << ex.what() << " wurde nicht gefunden"; lade_eine_default_config(); return; } lade_die_richtig_config(config); }Wie gesagt, wenn der runtime_error fliegt, wird er nicht gefangen? Wieso? Hat das was damit zu tun, dass der Error im Konstruktor fliegt und gefangen wird (werden sollte)? Aber es ist ja der Konstruktorbody, keine Elementinitialisierung, also sollte das ja ganz normal funktionieren.
Philipp
-
Mit folgendem Beispiel konnte ich den von dir geschilderten Fehler nicht nachvollziehen (Compiler TDM G++ 4.5.0):
#include <stdexcept> #include <iostream> class Foo { public: Foo(); private: int i; }; void WerfeException() throw (std::runtime_error) { throw std::runtime_error("abc"); } Foo::Foo() : i(4) { try { WerfeException(); } catch (std::runtime_error& e) { std::cout << "Exception gefangen " << e.what() << std::endl; } } int main() { Foo f; }Der Fehler scheint also woanders zu liegen.
-
Hmm, das scheint mit dem Rückgabetyp der Funktion zusammenzuhängen.
ist die Funktion void (wie in deinem Beipsiel) wird die exception tatsächlich gefangen. Ist sie hingegen std::string, wird terminate() aufgerufen...Zwei exceptions zur gleichen Zeit aktiv? Destruktor von std::string ?
-
Ich kann keinen Zusammenhang mit dem Rückgabewert erkennen. Die Möglichkeit, dass eine andere Exception fliegt kannst du aber prüfen indem du einfach mal alle anderen noch zusätzlich fängst.
-
Auch wenn ich catch(...) mache, kommt ein abort(). WTF? Irgendwas übersehe ich gerade. Kann es sein das std::ifstream::is_open() selbst eine Exception wirft?
-
Zeig doch mal ein vollständiges Minimalbeispiel, das das Problem reproduziert.
-
PhilippM schrieb:
Kann es sein das std::ifstream::is_open() selbst eine Exception wirft?
Laut Referenz nicht. Ich hab aber eben auch mal dein Beispiel getestet und das funktioniert wie von dir erwartet.
http://www.cplusplus.com/reference/iostream/ifstream/is_open/
-
Das funktioniert wie erwartet
#include <fstream> #include <string> #include <stdexcept> #include <iostream> std::string loadFile(const std::string& file_name) throw(std::runtime_error) { std::string buf, line; std::ifstream in(file_name.c_str(), std::ios_base::in); if(!in.is_open()) { throw std::runtime_error(file_name); } while(std::getline(in,line)) buf += line; return buf; } class Foo { public: Foo(const std::string& filename) { std::string bar; try { bar = loadFile(filename); } catch(std::runtime_error& ex) { std::cerr << ex.what() << " konnte nicht geöffnet werden"; mem = 0; return; } mem = 1; } private: int mem; }; class Other { public: Other():member("blub"){} private: Foo member; }; int main(int argc, char *argv[]) { Other o; 0; }Problem ist, wenn ich genau diesen Code
try { bar = loadFile(filename); } catch(std::runtime_error& ex) { std::cerr << ex.what() << " konnte nicht geöffnet werden"; mem = 0; return; }in meine Software paste, kommts zum abort().
Das kann ja eigentlich nur heißen, das zwei Excpetions fliegen, von denen ich nur eine gefangen kriege. Wenn ich catch(...) mache, ist das Ergebnis aber das gleiche.
Irgendwie steh ich gerade voll auf dem Schlauch.
Philipp
-
Mal eine andere Frage, bist du dir sicher, dass
is_open()an der Stelle die richtige Methode ist? Das eine zweite Exception fliegt ist unwahrscheinlich, wenn du sie nicht fangen kannst. Vielleicht darfst duis_open()nur auf eine vorhandene Datei anwenden?http://www.cplusplus.com/reference/iostream/ifstream/ifstream/
Dritter Absatz der Beschreibung.
-
Exception-Spezifikationen sind deprecated, weg damit!

-
Okay, diese zwei Funktionen gibts:
std::string loadFile(const std::string& file_name) throw(std::runtime_error) { std::string buf; std::string line; std::ifstream in(file_name.c_str(), std::ios_base::in); if(!in.is_open()) { throw std::runtime_error(file_name); } while(std::getline(in,line)) buf += line; return buf; } void foo() throw (std::runtime_error) { throw std::runtime_error("foo"); }Folgendes passiert:
try { //config = loadFile(config_file_name); // abort -> in der abort-Meldung steht der korrekte File-name foo(); // Exception wird korrekt gefangen } catch (std::runtime_error& ex){ Log() << Log::Fail << "Could not open " << ex.what() << ". SCS does not work without this file." << Log::endl; return; }Das heißt, aus loadFile() muss mehr als eine Exception kommen.
-
In der main hast du kein return drin
In der ursprünglichen loadFile auch nicht...Ich vermute mal, dass deine Exception gefangen wird, aber der
Stream nicht geflusht wird.std::cerr << ex.what() << " konnte nicht geöffnet werden" << std::endl;
-
kuck mal, ob 'irgendetwas' gefangen wird...
} catch(...){ }danach würde ich dann const std::exception& versuchen zu fangen
-
XSpille schrieb:
In der main hast du kein return drin
Stimmt. Da funktioniert aber auch alles
Ich vermute mal, dass deine Exception gefangen wird, aber der
Stream nicht geflusht wird.Das logfile wird aber geflusht.
Außerdem, selbst wenn der stream nicht geflusht würde, dürfte ja kein abort() kommen.
-
XSpille schrieb:
kuck mal, ob 'irgendetwas' gefangen wird...
} catch(...){ }danach würde ich dann const std::exception& versuchen zu fangen
Habe ich gerade probiert. auch die ellipse catcht nix.
-
XSpille schrieb:
Ich vermute mal, dass deine Exception gefangen wird, aber der
Stream nicht geflusht wird.std::cerr << ex.what() << " konnte nicht geöffnet werden" << std::endl;Ein std::endl bewirkt ein std::flush und ein '\n'.
-
tjatja schrieb:
XSpille schrieb:
Ich vermute mal, dass deine Exception gefangen wird, aber der
Stream nicht geflusht wird.std::cerr << ex.what() << " konnte nicht geöffnet werden" << std::endl;Ein std::endl bewirkt ein std::flush und ein '\n'.
Danke für die Info, allerdings ist mir das klar...
Ein Zeilenumbruch nach einer Meldung kann auch nichts schaden
-
Den Hinweis auf
fail()zu checken hast du gesehen?if (in.fail() || !in.is_open()) throw bla;
-
okay, habe den Fehler weiter eingegrenzt
std::string loadFile(const std::string& file_name) throw(std::runtime_error) { std::string buf, line; std::ifstream in(file_name.c_str(), std::ios_base::in); if(!in) { throw std::runtime_error(file_name); } return ""; // das funktioniert while(std::getline(in,line)) buf += line; return buf; }Man beachte, das die Funktion in jedem Fall einen leeren String zurückgibt.
Das Verhalten ist das erwartete: Für eine existente Datei gibt sie einen leeren String zurück, für eine nicht existente Datei kommt eine Exception, die auch gefangen wird.
Entferne ich das
return "";wird abort() aufgerufen im Falle einer nicht existenten Datei.
-
EDIT: ups... Falsche Vermutung
-
So geht's:
std::string loadFile(const std::string& file_name) throw(std::runtime_error) { std::string buf, line; std::ifstream in(file_name.c_str(), std::ios_base::in); if(in.fail() || !in) { throw std::runtime_error(file_name); return ""; } else { while(std::getline(in,line)) buf += line; return buf; } }Kann mir vielleicht einer erklären, wo hier das Problem war?
Ich hab nämlich keinen Schimmer, warum es jetzt geht.Philipp