Programiersprache für Anfänger



  • hustbaer schrieb:

    aber für die gegenstelle, oder das speichermedium, ist es ein bedeutsamer unterschied, ob die verbindung bzw. die datei im gegenseitigen einvernehmen geschlossen, radikal abgebrochen wird, oder ob gar nichts passiert. in den beiden letzten fällen ist datenverlust sehr wahrscheinlich

    Und nur erklär mir mal bitte was das mit RAII zu tun hat?

    es hat was damit zu tun, dass c++ destruktoren nahezu unbrauchbar sind. aber falls du darauf hinaus willst, dass man RAII wörtlich nehmen sollte: 'acquisition' und 'initialisation' sagt natürlich nix darüber aus, wie man irgendwas auch wieder vernünftig schliesst und eventuell auf fehlschläge reagiert.
    🙂



  • ~fricky schrieb:

    'acquisition' und 'initialisation' sagt natürlich nix darüber aus, wie man irgendwas auch wieder vernünftig schliesst und eventuell auf fehlschläge reagiert.

    Schlag doch mal vor, wie eine Software bei einem Fehlerfall im Sinne von "kann Datei nicht schließen" reagieren sollte/könnte.



  • ~fricky schrieb:

    es hat was damit zu tun, dass c++ destruktoren nahezu unbrauchbar sind.

    In dem Fall wo die C++ Destruktoren versagen ist auch C am Ende. Und viele Probleme an denen C krankt lassen sich deutlich konfortabler mittels Destruktoren lösen. Ja, C++ ist nicht der Heilige Gral, aber C mit Sicherheit ebenso wenig.

    Zum Rest: Sie Post von Badestrand...



  • Badestrand schrieb:

    ~fricky schrieb:

    'acquisition' und 'initialisation' sagt natürlich nix darüber aus, wie man irgendwas auch wieder vernünftig schliesst und eventuell auf fehlschläge reagiert.

    Schlag doch mal vor, wie eine Software bei einem Fehlerfall im Sinne von "kann Datei nicht schließen" reagieren sollte/könnte.

    'nen ähnlichen thread hatten wird schon mal. es gibt kein patentrezept für sowas. ja nach art und wichtigkeit der aktion muss individuell unterschieden werden, ob oder wie man auf fehlschläge reagiert. einfach immer free(), delete, close(), oder was auch sonst, in einen C++-destruktor zu packen und hoffen, dass alles gut geht, ist oft eine ganz schlechte idee.

    asc schrieb:

    Und viele Probleme an denen C krankt lassen sich deutlich konfortabler mittels Destruktoren lösen.

    destruktoren dürfen weder exceptions auslösen, noch können sie error-codes zurückgeben. das ist schon mal doof. ok, manchmal mag es ganz praktisch sein, eine funktion zu haben, die automatisch aufgerufen wird, bevor sich ein objekt in luft auflöst. aber mit diesen einschränkungen^^ ist das nicht wirklich komfortabel.
    🙂
    🙂



  • @hustbaer
    Hehe, du hast nun das vorweg genommen, worauf ich hinaus wollte:

    Es ist nun einmal auch ohne RAII nicht möglich, dass man diese Situationen allgemein sinnvoll behandelt. Und wenn man eine Speziallösung für die Behandlung eines solchen Falles hat, dann kann man sie auch wunderbar in einem RAII System implementieren.

    (Bin gespannt auf eure vermeintlich Exception sicheren Codes, die in jedem Fall vernünftig aufräumen und auf alle Fehler sinnvoll und angemessen reagieren können...)

    ~fricky schrieb:

    destruktoren dürfen weder exceptions auslösen, noch können sie error-codes zurückgeben.

    Aber sie können Fehler auf andere Arten melden. In C ist es ja auch üblich, dass die Funktionen den error-code nicht über den Rückgabewert melden, sondern nur melden, ob die Operation erfolgreich war oder nicht.

    Nach meiner Erfahrung sind eher die C++ Leute, die die wirklich über Exceptions nachgedacht haben. In Java zB gibt es ja Exceptions, die man noch nicht einmal fangen und behandeln darf und wegen dem mangelnden RAII ist es somit einfach nicht möglich Programme zu schreiben, die sich ausreichend gegen Fehler abzusichern.



  • 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.


Anmelden zum Antworten