"delete" und Referenzen :-?



  • hallo! ich hab ein Verständnisproblem bei der Heap-Speicherverwaltung 😕
    würd mich sehr freuen wenn jemand Zeit und Nerven hat, sich das anzugucken!
    aaalso:

    ...
    
    MyObject& MyFunction();              
    
    int main(int argc, char* argv[])
    {
       MyObject& horst = MyFunction();           
       cout << "horst.a = " << horst.a << endl;
       cout << "horst.b = " << horst.b << endl;
       delete &horst;			        // warum & ???
       return 0;
    }
    ...
    

    es fehlt noch der Code zu MyFunction, da wird einfach ein neues "MyObject"-Objekt auf dem Heap erzeugt und zurückgegeben, als Referenz.
    Meine Frage ist jetzt, warum ich in der delete-Zeile das & brauche ? Wird das als Dereferenzierungsoperator benutzt ? Oder hat das was damit zu tun, dass "horst" eine Referenz ist ? oder vielleicht beides ? Wann brauch man bei delete das &, und wann nicht ?
    Fragen über Fragen !

    viele grüße vom verwirrten herrn
    ponx



  • Du darfst bei Referenzen kein delete verwenden.

    Wie sieht denn Deine Funktion MyFunction im Inneren aus? Was gibt die denn als MyObject& zurück? Ich ahne wieder Schlimmes.



  • btw. halte ich es für schlecht, wenn man irgend wo Speicher reserviert dann eine Referenz auf den Speicher zurückzugeben. Das verführt doch dazu, dass man so was vergisst.

    (da doch lieber std::auto_ptr)



  • Der Code ist korrekt und müsste auch einwandfrei funktionieren,
    da der delete-operator nicht feststellen kann ob er direkt auf einen Zeiger zugreift oder auf die Adresse einer Referenz.
    Allerdings ist die Referenz nach dem delete schlimmer und gefährlicher als ein wilder Zeiger, da es keine Null-Referenzen gibt. Jeder spätere Zugriff auf die Referenz zieht undefiniertes Verhalten mit sich. Von daher ist dies eine schlechte Lösung.
    Wie kingruedi schon vorgeschlagen hat -> smart-pointer nutzen 🙂



  • Der Code ist korrekt

    Unter der Annahme, dass MyFunction etwa so:

    MyObject& MyFunction()
    {
    return *new MyObject();
    }
    

    implementiert ist, ist der Code zwar aus sicht von C++ korrekt, wer sowas schreibt, gehört aber trotzdem verhauen.

    Allerdings ist die Referenz nach dem delete schlimmer und gefährlicher als ein wilder Zeiger, da es keine Null-Referenzen gibt. Jeder spätere Zugriff auf die Referenz zieht undefiniertes Verhalten mit sich.

    Das ist imo ein nur sehr eingeschränkt gültiges Argument, da
    da auch der Zugriff auf ein nicht mehr vorhandenes Objekt über einen Zeiger undefiniertes Verhalten hat. Selbiges gilt für die Dereferenzierung des Nullzeigers.

    Einen Zeiger kann man natürlich nach dem delete wieder auf ein neues Objekt richten, aber das hat nichts speziell mit dieser Situation zu tun, sondern ist ein generelle Eigenschaft von Zeigern.

    Das Problem an delete &ref ist meiner Meinung nach auf konzeptioneller Ebene. Kein Mensch bindet ein Heap-Objekt an eine Referenz und löscht das Objekt dann über selbige. Das heißt 98.9% aller C++ Programmierer werden über ein
    delete &ref erstmal stolpern. Danach müssen sie sich sammeln und erstmal nachschauen, ob hier nicht ausversehen ein Nicht-Heap-Objekt gelöscht wird.
    Das alles lenkt von der eigentlichen Tätigkeit ab.



  • jojo dat, aber mit "gefährlicher als wilder zeiger" meine ich,
    dass man zeiger wenigstens fragen kann ob sie auf ein objekt verweisen.

    delete zeiger;
    zeiger = 0;
    ....
    if(zeiger) { foo(); }
    

    bei der version mit der "wilden referenz" bekommste da mehr probleme.

    delete &referenz;
    referenz = 0; // oh weh...
    ...
    if(referenz) { // ach du schande...
      bar();
    }
    

    Lasset uns an die Hände fassen und gemeinsam C++ dafür danken, dass so ne Kacke syntaktisch zulässig ist.
    Lesbarer Code is langweilig 😃



  • @Iterator
    Schon klar was du meinst.

    Nur halte ich Code wie:

    Iterator schrieb:

    delete zeiger;
    zeiger = 0;
    ....
    if(zeiger) { foo(); }
    

    in der Regel sowieso für Käse. In der Regel ist das Nullsetzen eines Zeigers nach dem delete nur eine Technik zur Verschleierung von Programmfehlern. Entweder ich fasse den Zeiger nach dem delete nicht mehr an oder ich lasse ihn gleich auf ein anderes Objekt zeigen. Dieses "ich setze den Zeiger lieber auf null, dann kann mir im Zweifelsfall nichts passieren (kein Doppel-Delete u.Ä.)" ist aber keine gute Idee und zeigt imo nur, dass man nicht gewillt ist richtig nachzudenken.

    Natürlich gibt es aber auch Ausnahmen wo Code wie oben sinnvoll ist. Nur das sind wie gesagt eher Ausnahmen.



  • Das ist bei einer 0..1 Aggregation schon sinnvoll.



  • Das ist bei einer 0..1 Aggregation schon sinnvoll.

    Ich bezweifle doch nicht, dass es solche Situationen gibt. Vorgestern habe ich selbst noch solchen Code geschrieben (in einem TransactionPtr).

    Nur halte ich das trotzdem eher für die Ausnahme. Und nebenbei: Bei diesen Ausnahmen muss man auch immer explizit mit Pointer arbeiten. In den Situationen wo man theoretisch auch mit Referenzen arbeiten könnte, gewinnt man durch das Nullsetzen nichts. Die Aussage, dass ein delete &ref deshalb gefährlicher ist, halte ich immernoch für zweifelhaft.



  • erstmal vielen Dank an alle für Eure Hilfe ! Der Code hat funktioniert und war aus einem (leider ziemlich schlechten) Lehrbuch. Dass sowas kein gängiger C++-Stil ist, beruhigt mich jedenfalls zutiefst ! 🙂 Vielen dank für den Tip und den Link mit auto_ptr !
    andy/ponx


Anmelden zum Antworten