Smart Pointer



  • Hallo,

    ich versuche schon seit nen paar Stunden eine Liste (mit Knoten) zu realisieren, die mit Smart Pointer funktionieren soll..

    da gibt glaub ich noch mehrere Fehler, aber im Moment häng ich bei
    "smartptr.h:48: error: ‘void smartPointer::operator=(const smartPointer&)’ is private"
    klar könnt ich den Teil auch in den public Bereich vorrübergehen kopiern.. das will der Compiler aber auch nicht

    hier mein Quellcode:

    #ifndef _SMARTPTR_H
    #define	_SMARTPTR_H
    
    #include <cassert>
    #include <iostream>
    
    using namespace std;
    
    class knoten {
    private:
        int info;
        knoten * next;
    public:
    
        int getInfo() {
            return info;
        }
    
        void setInfo(int i) {
            info = i;
        }
    
        knoten * getNext() {
            return next;
        }
    
        void setKnoten(knoten * p) {
            next = p;
        }
    
        knoten * get(void) {
            return this;
        }
    };
    
    class smartPointer {
    public:
        smartPointer(knoten *p);
        virtual ~smartPointer();
        knoten * operator->() const;
        knoten & operator*() const;
        smartPointer & operator=(knoten *p);
        operator bool() const;
        void loescheObjekt();
    private:
        int Anzahl;
        knoten* ZeigerAufObjekt;
        void operator=(const smartPointer&); // p1 = p2; verbieten
        smartPointer(const smartPointer&); // Initialisierung mit smartPointer verbieten
    };
    
    inline smartPointer::smartPointer(knoten *p = 0) {
        ZeigerAufObjekt = p;
        if (ZeigerAufObjekt != NULL) {
            Anzahl = 1;
        } else {
            Anzahl = 0;
        }
    }
    
    inline smartPointer::~smartPointer() {
        loescheObjekt(); // siehe unten
    }
    // Die Operatoren -> und * prüfen, ob sie auf ein Objekt verweisen;
    // wenn nicht wird Fehlermeldung ausgegeben
    
    inline knoten* smartPointer::operator->() const {
        assert(ZeigerAufObjekt);
        return ZeigerAufObjekt;
    }
    
    inline knoten& smartPointer::operator*() const {
        assert(ZeigerAufObjekt);
        return *ZeigerAufObjekt;
    }
    
    inline smartPointer& smartPointer::operator=(knoten* p) {
        assert(ZeigerAufObjekt == 0);
        // stellt sicher, dass nur ein freier
        // Zeiger verwendet wird; es kann also keine
        // verwitweten Objekte geben.
        ZeigerAufObjekt = p;
        return *this;
    }
    
    //inline knoten * smartPointer::operator=(const smartPointer&) {
    //    Anzahl++;
    //    return ZeigerAufObjekt;
    //}
    
    // Mit Hilfe dieses Typumwandlungsoperators wird ein Vergleichsoperator
    // definiert. Damit sind Abfragen möglich, die testen, ob ein smartPointer
    // auf ein Objekt zeigt oder nicht.
    
    inline smartPointer::operator bool() const {
        return bool(ZeigerAufObjekt);
    }
    
    inline void smartPointer::loescheObjekt() {
        delete ZeigerAufObjekt;
        ZeigerAufObjekt = 0; // neue Intialisierung
    }
    
    #endif	/* _SMARTPTR_H */
    

    main:

    #include <iostream>
    #include <stdlib.h>
    #include "smartptr.h"
    
    using namespace std;
    
    class Liste {
    private:
        smartPointer sp_pos; //    knoten *pos;
        smartPointer sp_pre_pos; //    knoten *pre_pos;
        smartPointer sp_anfang; //    knoten *anfang;
    
        void rek(knoten * p) {
            if (p->getNext() != NULL) {
                rek(p->getNext());
            }
            cout << p->getInfo() << endl;
        }
    
    public:
    
        Liste() {
            sp_pos = NULL;
            sp_pre_pos = NULL;
            sp_anfang = NULL;
        }
    
        void ins(int x) {
            smartPointer sp(new knoten); // knoten *p = new knoten; // erzeuge neuen knoten
            sp->setInfo(x); // Infowert wird x
            sp->setKnoten(sp_pos->get()); // next wird initialisiert mit alten P.-Zeiger
            // es wird also VOR dem aktuellen Element eingefügt
            if (sp_anfang == NULL) // Leere Liste
                sp_anfang = sp;
            if (sp_pre_pos != NULL) // Positionszeiger hat einen Vorgänger
                sp_pre_pos->setKnoten(sp->get());
            else // neues Element steht am Anfang
                sp_anfang = sp;
            sp_pos = sp; // Positionszeiger zeigt nun auf das neue Element
        }
    
        int get() { // liefere aktuelles Element
            return sp_pos->getInfo();
        }
    
        void del() { // Aktuelles Element löschen
            if (sp_pos != NULL) { // P.-Zeiger steht nicht am Ende
                if (sp_pre_pos != NULL) // P.-Zeiger steht nicht am Anfang
                    sp_pre_pos->setKnoten(sp_pos->getNext());
                else
                    sp_anfang = sp_pos->getNext(); // Anfang wird neu gesetzt
                //            delete sp_pos; // Speicher aufräumen
                if (sp_pre_pos != NULL)
                    sp_pos = sp_pre_pos->getNext(); // P.-Zeiger steht auf
                    // ehemaligem Nachfolger
                else
                    sp_pos = sp_anfang; // Pos-Zeige auf Anfang
            }
        }
    
        void reset() {
            // Positionszeiger an den Anfang setzen
            sp_pos = sp_anfang;
            sp_pre_pos = NULL;
        }
    
        void adv() {
            // Positionszeiger vorrücken
            if (sp_pos != NULL) {
                sp_pre_pos = sp_pos;
                sp_pos = sp_pos->getNext();
            }
        }
    
        bool end() { // Ende erreicht?
            return (sp_pos == NULL);
        }
    
        void ausgeben() {
            rek(sp_anfang->get());
        }
    };
    
    int main(int argc, char** argv) {
            Liste l;
            l.ins(5);
            l.ins(4);
            l.ins(3);
            l.ins(2);
            l.ins(1);
            cout << l.get();
            l.adv();
            cout << l.get();
            l.ausgeben();
        return 0;
    }
    


  • Hi Xeddon,

    was für eine Art smartpointer willst du denn proggn?

    Da dein Code relativ lang ist, geh ich erstmal auf das ein, was wir beim
    ersten Blick ins Auge fällt.

    void ins(int x) {
            smartPointer sp(new knoten); // knoten *p = new knoten; // erzeuge neuen knoten
    // ...
            sp_pos = sp; // Positionszeiger zeigt nun auf das neue Element
        }
    

    Du erstellst hier einen Smartpointer auf dem Stack.
    Am Ende versuchst dann diesen deinem Feld zuzuweisen, jedoch ist der Zuweisungsoperator nicht sichtbar.

    Wenn du ihn als public definierst, dann fehlt dir leider (wahrscheinlich) die
    Implementierung davon, weswegen dein Linker dann meckert.

    Als erstes solltest du mal erklären, warum dein pointer smart ist 🙂

    wegen der Zusatzinfos?

    Wie soll denn ein Kopieren des Smart-Pointers behandelt werden?



  • hiho,

    also beim Überfliegen ist mir mal das aufgefallen:

    smartPointer sp_pos; //    knoten *pos;
    smartPointer sp_pre_pos; //    knoten *pre_pos;
    smartPointer sp_anfang; //    knoten *anfang; 
    
    //...
    
            if (sp_anfang == NULL) // Leere Liste
                sp_anfang = sp;
            if (sp_pre_pos != NULL) // Positionszeiger hat einen Vorgänger
                sp_pre_pos->setKnoten(sp->get());
            else // neues Element steht am Anfang
                sp_anfang = sp;
            sp_pos = sp; // Positionszeiger zeigt nun auf das neue Element
    

    Die Zuweisungen in den "IFs" können ja nicht funktionieren wenn der operator=(const smartPointer&) private ist.



  • - Bezeichner nicht mit _ anfangen! (die sind reserviert)
    - kein using namespace std in Headerdateien!
    - Warum machst Du die Knoten-Klasse so kompliziert?

    struct node
    {
      int data;
      node* next;
    };
    

    ...tut es doch auch.

    - Der Konstrtuktor von smartPointer sollte explizit sein
    - Wozu hat smartPointer einen virtuellen Destruktor ?!
    - "operator bool() const" macht man nicht, siehe "safe bool idiom"
    - Den Defaultparameter für den Konstruktor solltest Du in die Klassendefinition verlagern

    Das ganze Zeug mit dem smartPointer solltest Du Dir wahrscheinlich sparen und es eher so machen:

    class list
    {
      node* first;
      node* last;
    public:
      list() : first(0), last(0) {}
      list(list const&);
      list& operator=(list const&);
      ~list();
      ...
    };
    
    list::~list()
    {
      while (first) {
        node* temp = first->next;
        delete first;
        first = temp;
      }
    }
    

    u.s.w.


Log in to reply