Pointer auf null testen hier sinnvoll?



  • µ schrieb:

    cooky451 schrieb:

    Was meinst du, passiert, wenn das zweite new int eine Exception wirft? Solche Fälle kommen durchaus vor.

    Das hast nichts mehr mit der Realität zu tun. Inwiefern interessiert denn noch Exception-Sicherheit, wenn das Allokieren von ein paar Byte fehl schlägt? Was genau will man in so einer Extremsituation noch retten?

    z.b. daten retten/speichern, die sich im laufe des programms angesammelt haben, bevor es zur out of memory situation kam.



  • @Hyde++
    p ist zum Zeitpunkt an dem die Exception geworfen wird vollständig konstruiert, also wird auch der Destruktor aufgerufen. Wie kommst du auf das Ende des Programms? Das passiert quasi sofort.

    µ schrieb:

    Das hast nichts mehr mit der Realität zu tun. Inwiefern interessiert denn noch Exception-Sicherheit, wenn das Allokieren von ein paar Byte fehl schlägt? Was genau will man in so einer Extremsituation noch retten?

    Es geht hier um sauberes Programmieren, da interessiert mich die Realität doch nicht. 🤡
    Aber mal ernsthaft: Das Objekt kann auch etwas anderes als ein int sein. Was ist, wenn da eine Datenbankverbindung nicht mehr geschlossen wird oder Ähnliches? (Was genau die Exception wirft ist für das Argument doch völlig unerheblich.) Und warum sollte ich auf 100%ige Sicherheit verzichten, wenn sie nichts kostet? C++ macht es einem so einfach, saubere und sichere Programme zu erstellen. Viel einfacher als jede andere mir bekannte Sprache; man muss sich einfach nur mal an ein paar kleine Regeln halten. Ich verstehe nicht was man dagegen haben könnte. 😕 (Und ich verstehe nicht, was daran so schwer ist, dass einige mehr oder weniger erfahrende Leute hier sich immer noch nicht daran halten.)



  • cooky451 schrieb:

    XSpille schrieb:

    Also ich habe in meinem Destruktor schon gelegentlich ein delete drin stehen...

    Fehler.

    Weswegen Fehler? 🤡

    cooky451 schrieb:

    XSpille schrieb:

    In dem Fall habe ich mit std::unique_ptr keinen Mehrwert, da es ja durch das delete im Destruktor eh exceptionsafe ist. (bei shared_ptr hat man natürlich einen Mehrwert)

    Denkste. Mal sowas gemacht?

    class foo
    {
      int* p_;
      int* q_;
    
    public:
      foo()
        : p_(new int)
        , q_(new int)
      {}
      ~foo()
      {
        delete p_;
        delete q_;
      }
    };
    

    Ich bin mir bewusst, dass es problematisch wird, wenn im zweiten new eine Exception fliegt. Allerdings stelle ich mal die Frage, warum du die Variablen dynamisch allokierst? Wann brauch man schonmal zwei Allokationen in einem Konstuktor? Ich dachte an setter, die den Besitz eines Objektes übernehmen. Da kann dann keine Exception fliegen und ein delete im Destruktor ist völlig exceptionsicher...

    struct foo{
        foo() : bar_ptr(nullptr){}
        ~foo() { delete bar_ptr; }
        void set_bar(std::unique_ptr<bar>&& bar){ bar_ptr = bar.release(); } // unique_ptr als Besitz-Kennzeichnung
        bar* bar_ptr;
    };
    


  • XSpille schrieb:

    Weswegen Fehler? 🤡

    Weil schlecht.

    XSpille schrieb:

    Ich bin mir bewusst, dass es problematisch wird, wenn im zweiten new eine Exception fliegt. Allerdings stelle ich mal die Frage, warum du die Variablen dynamisch allokierst?

    Um hier eben ein Beispiel hinzufrickeln? Was soll die Frage überhaupt, ist doch wohl mehr als offensichtlich welche Fälle mit diesem Beispiel gezeigt werden? 🙄

    XSpille schrieb:

    Wann brauch man schonmal zwei Allokationen in einem Konstuktor?

    Das betrifft jede Situation in der du 1. eine Ressource reservierst, die man wieder schließen muss und 2. danach irgendetwas machst, was eine Exception werfen könnte. Das kommt doch schon mal vor.

    XSpille schrieb:

    Ich dachte an setter, die den Besitz eines Objektes übernehmen. Da kann dann keine Exception fliegen und ein delete im Destruktor ist völlig exceptionsicher...

    Dann ist das in diesem einen Fall halt exceptionsicher. Es gibt auch noch mehr Fälle, die ohne Smartpointer sicher sind. Hat aber mit dem Punkt nichts zu tun. So musst du dir darüber Gedanken machen, und wenn du das mal vergisst, kabumm. Wenn du einfach immer einen Smartpointer nimmst, kann das nicht passieren. Da das keinen Nachteil hat*, folgt logisch dass man immer Smartpointer nutzt.

    * man muss eher weniger Code schreiben, und kann z.B. nicht vergessen Kopierkonstruktoren etc. private zu machen, bzw. man kann nicht aus versehen kopieren, weil das dann nicht kompiliert

    Ich könnte mich hier schon wieder selbst zitieren, ich verstehe nicht was daran so schwer ist, sich an diese simple Regel zu halten, die so viele offensichtliche Vorteile und quasi keine Nachteile hat.

    Dein Beispiel macht noch weiter deutlich wie schwachsinnig das Ganze wird. Der Code wäre viel simpler, wenn wenn bar_ptr ein Smartpointer wäre.

    Edit: Und warum zum Geier holst du dir den unique_ptr über eine rvalue Referenz? Oo



  • XSpille schrieb:

    Ich dachte an setter, die den Besitz eines Objektes übernehmen.

    Benutzt du RAII? Wie löst du den Fall, dass du den Pointer bereits im Konstrukor initialisieren musst?



  • cooky451 schrieb:

    Ein delete außerhalb der Standardbibliothek ist (zu 99.9999%?) ein Designfehler.

    Als ich mal einen custom deleter für einen smart pointer geschrieben habe, war das delete glaub nötig.



  • µ schrieb:

    cooky451 schrieb:

    Was meinst du, passiert, wenn das zweite new int eine Exception wirft? Solche Fälle kommen durchaus vor.

    Das hast nichts mehr mit der Realität zu tun. Inwiefern interessiert denn noch Exception-Sicherheit, wenn das Allokieren von ein paar Byte fehl schlägt? Was genau will man in so einer Extremsituation noch retten?

    Das hat viel mit der Realität zu tun. Zumindest mit meiner.
    Und zwar einfach deswegen, weil ich mich weigere mir bei jeder 2. Zeile (oder auch nur bei jeder 100. oder 100.) zu überlegen "könnte das mal relevant werden?". Weil das einfach zu viel Zeit frisst. Und vor allem über kurz oder lang mit an Sicherheit grenzender Wahrscheinlichkeit zu schlechtem Code führt.

    Wenn es um Exception-Safety geht, dann mach' ich das einfach.
    Ob es 1 MB oder 1 int oder 1 char ist ist mir dabei dann so richtig vollkommen egal.

    Ich habe mir dadurch auch angewöhnt überhaupt etwas anders zu programmieren. Dadurch bin ich dann auch an den Stellen schneller, wo man ganz sicher nicht auf Exception-Safety verzichten kann. Unterm Strich brauch' ich vermutlich trotzdem ein wenig länger, aber ich meine es zahlt sich aus: weniger Fehler, besser wartbarer Code, ...



  • designfehler schrieb:

    cooky451 schrieb:

    Ein delete außerhalb der Standardbibliothek ist (zu 99.9999%?) ein Designfehler.

    Als ich mal einen custom deleter für einen smart pointer geschrieben habe, war das delete glaub nötig.

    Das fällt dann in die 0.00001%. 🤡



  • cooky451 schrieb:

    Und dann wirf gleich noch mal einen Blick auf std::unique_ptr. Ein delete außerhalb der Standardbibliothek ist (zu 99.9999%?) ein Designfehler.

    Jetzt geht das wieder los ... Fanatiker.



  • Wo er Recht hat, hat er Recht. 😉



  • Im Umkehrschluss bedeutet das, alle Programme ohne Smartpointer haben einen Designfehler? Was ist mit jenen aus dem Jahr 2005 oder frueher? Ist C zu verwenden an sich auch ein Designfehler? Woher kommt der Wert 99.99...%, warum nicht 80%?



  • Den Umkehrschluss kannst Du nicht machen. Vielleicht braucht irgendein Programm ja auch überhaupt keine Zeiger, somit auch kein delete und somit auch keine Smartpointer. 😉

    Ich benutze die auch nicht ständig, auch unique_ptr nicht. Aber mein aktuelles Projekt lehrt mich, dass die Vorteile zu groß sind. Zu leicht vergisst man Mal ein delete oder macht aus Versehen eine unerwünschte Kopie (bzw. vergisst das Privatisieren von copy-ctor & operator=). Da kann mir jetzt jeder sagen "Dann programmierst Du halt schlecht.". Umso größer das Projekt wird, umso wahrscheinlicher ist es jedoch, dass es in einem Promille der Fälle passiert und oft sind damit verbundene Fehler schwer zu finden (oder niemand merkt gar, dass er ein delete vergaß und erzeugt Speicherlecks).



  • Eisflamme schrieb:

    Den Umkehrschluss kannst Du nicht machen. Vielleicht braucht irgendein Programm ja auch überhaupt keine Zeiger

    Ähemm.. bitte richtig formulieren 🙂



  • Bitte sagen, was falsch formuliert ist.

    Und hast Du ein Verständnisproblem oder ist die Aussage nicht vielmehr komplett klar, sodass es keinen Grund dazu gibt darauf rumzuhacken?



  • Ich glaube es ist Zeit, jegliche 99%-Glaubenskriege und Formulierungs-Haarspaltereien abzubrechen. Wenn ihr Spaß dran habt, macht per Mail weiter. Bitte back to topic 🙂



  • ...rumzuhacken

    ... Hacker...
    🕶



  • Eisflamme schrieb:

    Bitte sagen, was falsch formuliert ist.

    Und hast Du ein Verständnisproblem oder ist die Aussage nicht vielmehr komplett klar, sodass es keinen Grund dazu gibt darauf rumzuhacken?

    Also,

    ich habe ich Programmen mit Ogre Unmassen von Zeigern. Und kein einziges delete . Weil Zeiger und selbstständiges Verwalten eben nicht mit einander verknüpft sind, dachte das wäre mehr oder weniger offensichtlich 😕 🙂



  • Themenbezogen präzisiere ich Mal meine Aussage, weil meine Formulierung offensichtlich nicht verstanden wird. Ich hoffe, das ist im korrekten Rahmen.

    Ich meinte mit meiner Aussage, dass es auch Programme ohne Zeiger (ohne Notwendigkeit für Zeiger, weil alles über den Stack oder Container verwaltet wird) geben kann. Für diesen Fall wäre es also gar nicht notwendig sich die Frage zu stellen, ob man einen Smartpointer oder einen rohen Zeiger nehmen muss. Der Umkehrschluss, dass "delete bedeutet immer Designfehler" daher immer bedeutet "ein Programm ohne Smartpointer ist automatisch misdesigned" ist also nicht zwingend.

    Übrigens glaube ich, dass wir seit Seite 1 einen Glaubenskrieg haben, denn OPs Frage wurde von cooky bereits beantwortet und Enumerator hat sich seitdem nicht mehr gemeldet, also es vermutlich verstanden.



  • Eisflamme schrieb:

    Übrigens glaube ich, dass wir seit Seite 1 einen Glaubenskrieg haben, denn OPs Frage wurde von cooky bereits beantwortet und Enumerator hat sich seitdem nicht mehr gemeldet, also es vermutlich verstanden.

    Dann kann ich ja zumachen 🙂

    Da evtl. noch Diskussionsbedarf besteht, habe ich den Thread auf Wunsch eines Forenmembers wieder geöffnet. Aber: bitte nur zum originalen Topic posten.


Anmelden zum Antworten