Smartpointer



  • Hey ihr,

    Ich hab mal wieder ne Frage an euch 😉
    Verstehe nämlich in meinem C++-Buch so ein Verfahren nicht.
    Und zwar geht es da um smartpointer.
    Das wenn ich beispielsweise das Objekt 'hal' einen Zeiger enthält:

    int *i = new int(42);
    hal(&i);
    del i;
    

    hal nun einen hängenden Zeiger enthält.
    Zur Lösung des Problems schlägt mein Buch vor eine Zählerklasse zu definieren, welche den entsprechenden Zeiger und eine Zählvariable enthält.
    Diese ist mit 'hal' befreundet.
    Nun zählt die Zählerklasse wie viele 'hal's es gibt und löscht das entsprechende Objekt sobald der Zähler auf 0 steht.
    Das ist jedoch irgendwie doch garnicht sinnvoll, weil es ja immer noch sein kann, dass irgendein doofer User "del i" schreibt und das Objekt somit trotzdem gelöscht wird.

    Ich verstehe nicht ganz den Sinn.
    Kann mir jemand helfen?

    cya
    David



  • Wenn du mit einem Smart-Pointer arbeitest, darfst du ihn nicht mehr manuell löschen (durch delete-Aufrufe). Wer es trotzdem macht, hat schnell ein großes Problem.

    (btw, was soll uns dieser Quelltext eigentlich sagen?)



  • Ich dachte smartpointer wären einfach dafür, dass das betreffende Objekt erst dann gelöscht wird, wenn es keine anderen Objekte desselben Typs mehr gibt.
    Um dies zu managen wäre dann die Zählerklasse etc da.
    Allerdings kann ich doch auch einfach die Smartpointer weglassen und den Zeiger auch nicht manuell löschen.

    Der Quelltext war nur dafür da, um zu zeigen, wie ein hängender Zeiger entsteht. Damit ihr ein Beispiel habt.



  • Smart-Pointer sind dafür da, um sicherzustellen, daß und wann ein mit new angelegtes Objekt wieder freigegeben wird. Dafür gibt es verschiedene Strategien, die sicherstellen, daß genau ein "Zeiger" das delete aufrufen wird (std::auto_ptr, boost::shared_ptr, boost::scoped_ptr, um mal ein paar Varianten zu nennen). Aber alle gehen davon aus, daß niemand sich an ihnen vorbeimogelt und ihnen ihr Objekt unter dem Hintern weglöscht - wenn du das doch machst, fliegt dir vermutlich jede Smart-Pointer Klasse um die Ohren - egal welche Sicherheitsvorkehrungen sie getroffen hat.



  • 777 schrieb:

    Ich dachte smartpointer wären einfach dafür, dass das betreffende Objekt erst dann gelöscht wird, wenn es keine anderen Objekte desselben Typs mehr gibt.

    Ja, Smartpointer sind dazu da sich um sich um die Freigaben zu kümmern. Aber manche Smartpointer sind für Einzelinstanzen zuständig, manche haben Referenzzählung...

    Nur kannst du immer mit manuellen Mitteln das Konzept zerstören.

    777 schrieb:

    Um dies zu managen wäre dann die Zählerklasse etc da.
    Allerdings kann ich doch auch einfach die Smartpointer weglassen und den Zeiger auch nicht manuell löschen.

    Wenn du einen Smartpointer einsetzt verzichtest du auf manuelle Speicherfreigabe, und überlässt dies den Smartpointer.

    Wenn du ohne Smartpointer arbeitest verzichtest musst du dich um die manuelle Speicherfreigabe kümmern, alles andere wäre falsch.

    777 schrieb:

    Der Quelltext war nur dafür da, um zu zeigen, wie ein hängender Zeiger entsteht. Damit ihr ein Beispiel habt.

    Besser ist es grundsätzlich bei der Initialisierung des Smartpointerns das new zu verwenden ohne Umweg über einen traditionellen Pointer.

    z.B. boost::scoped_ptr<int> dynZahl(new int(4));

    Was man aber machen kann damit kein Anwender "delete" einsetzt ist es, der Klasse die verwaltet wird den Smartpointer als friend zu definieren und den Destruktor private zu machen. ABER: Dann lässt sich die Klasse nur noch mit Smartpointern verwenden.

    cu André



  • Ach und noch ein Nachtrag:

    Verwendungszweck von Smartpointern:

    Naheliegend: Wenn der Zeiger an mehreren Stellen verwendet werden soll, und mit der letzten Instanz gelöscht werden soll. Dies macht man mit einen Smartpointer mit einer wie auch immer gearteten Referenzzählung (z.B. boost::shared_ptr).

    Wichtiger, aber von dir garnicht genannt: Sicherheit bei Exceptions etc. Nehmen wir einfach mal eine Klasse mit mehreren Zeigern als Member an, die im Konstruktor initialisiert werden:

    Variante 1: Ohne Smartpointer

    class A
    {
        private:
            B* member1;
            B* member2;
        public:
            A()
            :   member1(new B),
                member2(new B)
            {}
    };
    

    So, was kann passieren: Nehmen wir einfach mal an das beim Versuch den zweiten Member zu allozieren eine Exception geworfen wird. Dann ist member1 aber bereits vorhanden, die Konstruktion wird abgebrochen. Der Speicher für den Zeiger wird zwar freigegeben, aber nicht für den Inhalt.

    Variante 2: Mit Smartpointer

    class A
    {
        private:
            boost::scoped_ptr<B> member1;
            boost::scoped_ptr<B> member2;
        public:
            A()
            :   member1(new B),
                member2(new B)
            {}
    };
    

    Nun wird bei einem Fehler auch die Speicherfreigabe durchgeführt.

    Das ganze kann man auch auf Funktionen anwenden. Nehmen wir an du hast eine Längere Funktion die eine Exception werfen kann, für die aber die Funktion selbst keine Behandlung machen kann. Entweder musst du mit try/catch arbeiten wenn du lokal Speicher allozierst, oder du setzt Smartpointer ein.

    cu André



  • Ich denk ich hab jetzt schon verstanden, was die Smartpointer bringen.
    Allerdings hab ich die zweite Methode für Smartpointer noch garnicht im Buch gemacht- bin aber trotzdem froh über eure Antworten.
    Danke 😉 abc



  • Noch eine Frage... wäre es nicht möglich Smartpointer auch mit hilfe eines statischen Objektes der Klasse zu erzeugen.
    Dieses statische Objekt dient dann als Zähler.
    Zeiger & Counter werden einfach mit 'static' versehen und schon braucht man keine andere Klasse mehr?

    Edit: Ohh meine Frage hat sich schon erledigt.
    Es kann ja auch durchaus sein, dass ich zur selben Klasse mehrere unterschiedliche Objekte haben will. Und nur wenn ich mein Objekt kopiere soll es tatsächlich auf die selbe Stelle im Speicher verweisen 😉


Anmelden zum Antworten