Programiersprache für Anfänger



  • rüdiger schrieb:

    In Java zB gibt es ja Exceptions, die man noch nicht einmal fangen und behandeln darf

    Das ist nachweislich falsch.

    und wegen dem mangelnden RAII ist es somit einfach nicht möglich Programme zu schreiben, die sich ausreichend gegen Fehler abzusichern.

    Auch das halte ich für ein Gerücht. Es ist in Java zwar umständlicher als nötig und mit ein wenig Tipparbeit verbunden, aber nicht unmöglich.



  • rüdiger schrieb:

    Nach meiner Erfahrung sind eher die C++ Leute, die die wirklich über Exceptions nachgedacht haben.

    naja, dass sogar das auslösen einer exception in einem constructor unvorhersehbare probleme mit sich bringen kann und z.b. dass exceptions einfach stillscheigend ignoriert werden können, zeugt nicht gerade von weitsicht. aber wer weiss, vielleicht wars ja auch absicht, damit c++ programmierer was zum knobeln haben und nicht beim coden einschlafen.
    🙂



  • ~fricky schrieb:

    rüdiger schrieb:

    Nach meiner Erfahrung sind eher die C++ Leute, die die wirklich über Exceptions nachgedacht haben.

    naja, dass sogar das auslösen einer exception in einem constructor unvorhersehbare probleme mit sich bringen kann und z.b. dass exceptions einfach stillscheigend ignoriert werden können, zeugt nicht gerade von weitsicht.

    Wieso diskutieren wir eigentlich mit jemanden, der sich mit C++ nicht auseinander setzt?

    Wenn man sich mit C++ auseinander setzen würde, wüsste man das ein C++ Konstruktor Exceptionsicher gemacht werden kann (und wie ich finde ist dies nicht einmal wirklich schwer, und zudem merklich leichter als eine tiefe if/else Schachtelung unter C bestehend aus Allokationen und Freigaben zu überblicken und Fehlerfrei zu halten).

    cu André



  • ~fricky schrieb:

    naja, dass sogar das auslösen einer exception in einem constructor unvorhersehbare probleme mit sich bringen kann

    Man muß sich natürlich mit Exceptions auseinandersetzen, daß mag jemanden schwerfallen, der die meiste Zeit mit einer Programmiersprache verbringt, die keine Exceptions kennt. Aber es bleibt festzuhalten, es ist möglich.



  • ~john schrieb:

    DEvent schrieb:

    ~john schrieb:

    Es ist lediglich erforderlich, daß der Destruktor fehlerfrei funktioniert.

    Wenn du externe Resourcen hast, dann kann immer was passieren. Nenn mir doch ein Beispiel, bei dem wirklich kein Fehler vorstellbar ist. (ein Socket kann nicht geschlossen werden, eine Datei nicht geschrieben/geschlosen, usw.). Deswegen muss eine close()-Methode dabei sein, die eine Exception werfen kann, weil eben ein destructor nichts werfen darf. Und deswegen ist auch RAII hier vollkommen nutzlos.

    Es gibt zwei Möglichkeiten mit einer close Methode.

    • Durch die Exception wird der Codeblock verlassen, ohne die close Methode auszuführen -> Resourcenleck
    • Über einen Exceptionhandler wird die Closemethode im Falle einer Exception trotzdem ausgeführt. In diesem Fall muß die Methode "close()throw()" sein. Denn wenn close eine Exception werfen darf, dann führt das instantan zum Aufruf von unexspected(). Daher kann man in einem Destruktor oder in einer close Methode gleich unexspected aufrufen, es ändert am Ergebnis nichts. Viel mehr sollte man sich Gedanken machen, wie man über die richtige Lebensdauer eines Objekts solche Probleme vermeidet bzw. man muß sich überlegen wie man die Kuh trotzdem vom Eis holt.

    Wo ist den das Problem mit einer close() Funktion/Methode?

    int main
    {
        FileStream stream = FileStream(datei_name);
        try {
            stream.write("irgendwelche Daten");
        }
        catch (...) {
            try { stream.close(); }
            catch (...) { 
                openDialog("Error:", "Achtung, konnte die Datei 'foo' nicht schliessen, moeglicherweise Datenverlust. Fuehren Sie fsck aus."); 
            }
        }
    }
    

    Wie sieht den das ohne eine close() aus:

    int main
    {
        FileStream stream = FileStream(datei_name);
        try {
            stream.write("irgendwelche Daten");
        }
        catch (...) {
            throw();
        }
    } // hier wird FileStream::~FileStream() aufgerufen, das eine Exception wirft, weil es ein Hardwaredefekt
      // oder ein korrumpiertes Filesystem gab. Das Programm stuertzt einfach ab, weil man die
      // Exception nicht fangen kann
    

    @rüdiger: Exceptions in C++ ist das kaputeste was ich bis her gesehen habe. Zum einen darf man alles werfen (int, char*, Klassen, float, usw) und zum anderen sind C++ Exceptions sowieso nutzlos, weil man den call-Stack verliert. Ebenso hat C++ keine Speicherverwaltung, so das man die ehrenvolle Aufgabe hat nach einer Exception Speicherlecks zu suchen.



  • Exceptions in C++ ist das kaputeste was ich bis her gesehen habe. Zum einen darf man alles werfen (int, char*, Klassen, float, usw) und zum anderen sind C++ Exceptions sowieso nutzlos, weil man den call-Stack verliert.

    Was soll das heißen?

    Ebenso hat C++ keine Speicherverwaltung, so das man die ehrenvolle Aufgabe hat nach einer Exception Speicherlecks zu suchen.

    Ehm, aber nicht wenn man die Objekte auf dem Stack anlegt oder einen Smartpointer wie auto_ptr oder scoped_ptr benutzt.
    Bleiben ja nicht mehr viele Möglichkeiten übrig, um selber aufräumen zu müssen.



  • Klassischer Schuß nach hinten 😃

    DEvent schrieb:

    Wo ist den das Problem mit einer close() Funktion/Methode?

    int main
    {
        FileStream stream = FileStream(datei_name);
        try {
            stream.write("irgendwelche Daten");
        }
        catch (...) {
            try { stream.close(); }
            catch (...) {
                openDialog("Error:", "Achtung, konnte die Datei 'foo' nicht schliessen, moeglicherweise Datenverlust. Fuehren Sie fsck aus.");
            }
        }
    }
    

    Na, zum Beispiel hast du da ein Speicherleck eingebaut (catch(...) ist nicht finally!). Wenn die Ressource, wie es sich gehört, im Destruktor freigegeben würde, wäre das nicht passiert.

    DEvent schrieb:

    Wie sieht den das ohne eine close() aus: [...]

    void realMain (void)
    {
        FileStream stream (datei_name);
        stream.write ("irgendwelche Daten");
    }
    
    int main (void)
    {
        try
        {
            realMain ();
            return 0;
        }
        catch (std::exception& e)
        {
            std::cerr << "Fehler: Exception vom Typ " << typeid (e).name () << ": "
                      << e.what () << std::endl;
            return 1;
        }
        catch (...)
        {
            std::cerr << "Fehler: Unbekannte Exception" << std::endl;
            return 1;
        }
    }
    

    So etwas enthält praktisch jedes ernstzunehmende Programm, und viele Frameworks stellen das auch automatisch bereit.

    DEvent schrieb:

    Zum einen darf man alles werfen (int, char*, Klassen, float, usw)

    In diesem Punkt stimme ich zu. Das ist nicht nur nutzlos, sondern auch äußerst hinderlich.

    DEvent schrieb:

    und zum anderen sind C++ Exceptions sowieso nutzlos, weil man den call-Stack verliert.

    Nö.

    DEvent schrieb:

    Ebenso hat C++ keine Speicherverwaltung, so das man die ehrenvolle Aufgabe hat nach einer Exception Speicherlecks zu suchen.

    Das ist, wie mein Vorposter bereits feststellte, nicht der Fall, wenn man RAII richtig einsetzt, anstatt close()-Methoden zu benutzen.

    close()-Methoden sind insbesondere in C++ eher ein Designfehler, denn sie haben einen gravierenden Nachteil: sie versetzen ein Objekt in einen Zustand, in dem der Aufruf seiner Methoden ungültig ist. Das Aufräumen sollte nur der Destruktor übernehmen.



  • DEvent schrieb:

    Wo ist den das Problem mit einer close() Funktion/Methode?

    int main
    {
        FileStream stream = FileStream(datei_name);
        try {
            stream.write("irgendwelche Daten");
        }
        catch (...) {
            try { stream.close(); }
            catch (...) { 
                openDialog("Error:", "Achtung, konnte die Datei 'foo' nicht schliessen, moeglicherweise Datenverlust. Fuehren Sie fsck aus."); 
            }
        }
    }
    

    Wie sehe der Code aus, wenn du mehr als eine Datei (bzw. andere Ressource) verwalten musst?

    Ansonsten hat audacia ja schon genug dazu gesagt.



  • DEvent schrieb:

    Exceptions in C++ ist das kaputeste was ich bis her gesehen habe.

    naja, ein bisschen kann man struppi verstehen. longjmp/setjmp passen nicht so recht zu einer sprache, die objektorientierung unterstützt und da hat er einfach ein strukturiertes gerüst darum gebaut. du solltest auch bedenken, dass die ersten c++ compiler (z.b. cfront) aus c++ c-code machten, und diesen dann durch einen c-compiler scheuchten, was einschränkungen mit sich bringt, die er beim erfinden von c++ berücksichtigen musste. irgendwann später fiel den usern auf, dass c++ exceptions im zusammenhang mit anderen konstrukten teilweise seltsames verhalten an den tag legen, aber das ist nicht nur (in c++) bei exceptions so. alles in allem ist c++ zwar nur ein 'nice try', aber, wie ich finde, können sich viele user trotzdem gut damit arrangieren (sieht man ja auch an einigen beiträgen hier).
    🙂



  • Nur mal am Rande, Struppi hat die Exceptions nicht erfunden, die gab es vorher zumindest schon in Ada.



  • die gab es schon in pl/1, also über 15 Jahre vor ada (1980)



  • selbst die CPU kennt exceptions. versuch mal durch 0 zu teilen 🙂



  • gfhgfh schrieb:

    selbst die CPU kennt exceptions. versuch mal durch 0 zu teilen

    'ne cpu kann sich sowas auch erlauben. aber stell dir mal vor, c++ würde solche exceptions auch abfangen. dann wären rechenoperationen aber höllisch lahm.
    🙂



  • C++ Exceptions sind aber bei weitem mehr als CPU Exceptions. Thema Stack-Unwinding etc.
    Die Beiden zu vergleichen ist wie einen Ziegelstein mit einem Haus zu vergleichen. Man kann einen Ziegel verwenden wenn man ein Haus bauen möchte, ja, aber an einem Haus ist bei weitem mehr dran als nur ein (oder ein paar) Ziegel.



  • Nicht nur das. CPU-Exceptions entstehen bei ungültigen Befehlen und dergleichen automatisch, die sind also eher mit Signalen zu vergleichen. C++-Exceptions werden durch throw geworfen. Man kann auch beides verheiraten, siehe Windows-SEH, muss man aber nicht.



  • Bashar schrieb:

    C++-Exceptions werden durch throw geworfen. Man kann auch beides verheiraten, siehe Windows-SEH...

    windoofs-seh ist ein ins os integriertes feature, um hardware-exceptions im eigenen programm abfangen zu können. eine sehr praktische sache übrigens, die sogar im kernel funktioniert. mit 'RaiseException' kann man das seh auch manuell antriggern (ähnlich 'throw'), aber mit c++ exceptions hat es absolut nix zu tun.
    🙂



  • Die SEH-Exceptions werden doch in C++ auf Exceptions abgebildet, oder nicht? Falls nicht, hab ich nix gesagt, ich kenn mich damit nicht aus 🙂



  • Bashar schrieb:

    Die SEH-Exceptions werden doch in C++ auf Exceptions abgebildet, oder nicht?

    ja, in den ms-compilern jedenfalls.
    🙂



  • Bashar schrieb:

    Die SEH-Exceptions werden doch in C++ auf Exceptions abgebildet, oder nicht?

    Nein, umgekehrt: die meisten Windows-Compiler implementieren Exceptions mithilfe von SEH. Mit catch (...) fängt man dennoch (ausgenommen in MSVC, und auch da nur, wenn man einen bestimmten Kompatibilitäts-Switch angibt) keine Windows-, sondern nur Sprachexceptions.

    Eine weitere Ausnahme sind VCL-Programme. Die VCL installiert einen Exception-Filter, der OS-Exceptions in Delphi-Exceptions umwandelt (mehr dazu hier).



  • Wenn der Compiler also Exceptions nicht mit SEH implementiert, könnte man dann SEH nicht mit try..catch behandeln? Wie würde das gehen, mit speziellen Handler-Funktionen?


Anmelden zum Antworten