abstrakte klassen



  • krümelkacker schrieb:

    TNA schrieb:

    Wie schreibt man denn einfach eine Smart-Pointerklasse wenn der Compiler keine Move-Semantik kennt?

    Das ist ja eigentlich nur ein Problem im Fall unique_ptr.

    Dann braucht man aber einen reference counter. Das ist dann deutlich aufwendiger und hat zusätzlichen Overhead den man eigentlich nicht benötigt. Auch muss man dann bedenken, dass so ein Pointer nicht Threadsicher ist wie shared_pointer.



  • sorry, ich glaube ich stehe iwie auf dem schlauch

    gibt es denn irgendwelche probleme wenn ich

    template<class T>
    class wrapper
    {    
        T *ptr;
    public:
        wrapper() : ptr(NULL) {}
        wrapper(T *object) : ptr(object) {}
        ~wrapper() {this->clear();}
        void set(T *object) {this->clear(); ptr = object;}
        T& get() {return *ptr;}
        T const& get() const {return *ptr;}
        void clear() {if(ptr != NULL) delete ptr;}
    };
    

    mache und danach den vektor mit wrappern fülle? (abgesehen vom mehraufwand beim schreiben)



  • thomas 434 schrieb:

    sorry, ich glaube ich stehe iwie auf dem schlauch

    gibt es denn irgendwelche probleme wenn ich

    template<class T>
    class wrapper
    {    
        T *ptr;
    public:
        wrapper() : ptr(NULL) {}
        wrapper(T *object) : ptr(object) {}
        ~wrapper() {this->clear();}
        void set(T *object) {this->clear(); ptr = object;}
        T& get() {return *ptr;}
        T const& get() const {return *ptr;}
        void clear() {if(ptr != NULL) delete ptr;}
    };
    

    mache und danach den vektor mit wrappern fülle? (abgesehen vom mehraufwand beim schreiben)

    Jede Menge Probleme entstehen dabei.
    Ich sag nur: kopieren.



  • Nur, falls du es noch nicht gemerkt hast: du versuchst gerade, einen "Smart Pointer" nachzuprogrammieren.


  • Mod

    thomas 434 schrieb:

    sorry, ich glaube ich stehe iwie auf dem schlauch

    gibt es denn irgendwelche probleme wenn ich
    [...]
    mache und danach den vektor mit wrappern fülle? (abgesehen vom mehraufwand beim schreiben)

    Ja. Du hast gerade so ziemlich alles falsch gemacht, was man bei Ressourcenhaltern falsch machen kann. Regel der großen Drei nicht beachtet, esoterische Vorstellungen über Nullzeiger, komische Initialisierung.



  • was meinst du mit "esoterische Vorstellungen über Nullzeiger, komische Initialisierung."? die regel mit dem zuweisungsoperator / kopierkonstruktoer kenn ich, ist mir in der eile entgangen, genau so wie dass ich in der clear funktion den zeiger auf NULL setzen muss.


  • Mod

    thomas 434 schrieb:

    was meinst du mit "esoterische Vorstellungen über Nullzeiger, komische Initialisierung."? die regel mit dem zuweisungsoperator / kopierkonstruktoer kenn ich, ist mir in der eile entgangen, genau so wie dass ich in der clear funktion den zeiger auf NULL setzen muss.

    komische Initialisierung: Mir fehlt eben alles, was der unique_ptr der Standardbibliothek/Boost kann. Dies ist sicherlich der kleinste Kritikpunkt, da es nur Komfort ist, der sich hinzufügen lässt. Die fehlende Nichtbeachtung der großen Drei ist hingegen ein handfester technischer Fehler, wegen dem man so etwas gerade nicht selber programmiert.

    Der Kram mit den Nullzeigern zeigt, dass du ein paar Grundlagen nicht kennst oder falsch verstanden hast. Oder wahrscheinlicher: Bei jemandem abgeschrieben hast, der sich nicht auskennt. Um das genauer heraus zu finden: Erklär mal Zeilen 6 und 12.



  • ich dachte mir, wenn man einen vektor mit xy tausend einträgen macht, den speicher aber auf ein mal statt nach und nach zu allozieren möchte, so muss der wrapper auch einen zustand haben, indem er kein objekt "hält". dies ist gegeben wenn der zeiger auf NULL zeigt.

    infolge dessen muss natürlich vor dem löschen beachtet werden ob der wrapper ein objekt hütet oder ob gar kein objekt alloziert wurde, so wird vor dem löschen geprüft ob der zeiger wirklich != NULL ist. in zeile 12 ist mir wie gesagt ein fehler unterlaufen, nach dem delete sollte natürlich der ptr zwangsweise auf NULL gesetzt werden.



  • template<class T> 
    class wrapper 
    {     
        T *ptr;
    public:
        wrapper() {ptr = new T;}
        wrapper(wrapper<T> const& rhs) {ptr = new T; *ptr = rhs.get();}
        ~wrapper() {delete ptr;}
        wrapper& operator= (wrapper const& rhs) {*ptr = rhs.get(); return *this;}
        T& get() {return *ptr;} 
        T const& get() const {return *ptr;} 
    };
    

    hier eine ein bisschen bessere realisierung


  • Mod

    thomas 434 schrieb:

    template<class T> 
    class wrapper 
    {     
        T *ptr;
    public:
        wrapper() {ptr = new T;}
        wrapper(wrapper<T> const& rhs) {ptr = new T; *ptr = rhs.get();}
        ~wrapper() {delete ptr;}
        wrapper& operator= (wrapper const& rhs) {*ptr = rhs.get(); return *this;}
        T& get() {return *ptr;} 
        T const& get() const {return *ptr;} 
    };
    

    hier eine ein bisschen bessere realisierung

    Das funktioniert so aber nicht mit polymorphen Typen. Und gerade wegen diesen wird der Aufwand ja überhaupt betrieben.



  • Ich hatte mal selbst 'nen clone_ptr gebastelt, finde den aber gerade nicht. Aber die Version war eh nicht C++98 oder C++03 kompatibel. Also hier mal eine Skizze für einen recht einfachen clone_ptr:

    template<class T>
    class clone_ptr
    {
    public:
       explicit clone_ptr(T* p=0) : ptr(p) {}
       ~clone_ptr() {delete ptr;}
       clone_ptr(clone_ptr const& x) : ptr(!x ? 0 : x->clone()) {}
       clone_ptr& operator=(clone_ptr temp) {swap(temp); return *this;}
       void swap(clone_ptr & other) {std::swap(this->ptr,other.ptr);}
       friend void swap(clone_ptr & a, clone_ptr & b) {a.swap(b);}
       T* release() {T* result=ptr; ptr=0; return result;}
       void reset(T* p=0) {clone_ptr temp (ptr); ptr=p;}
       bool operator!() const {return !ptr;}
       T const& operator*() const {return *ptr;}
       T      & operator*()       {return *ptr;}
       T const* operator->() const {return ptr;}
       T      * operator->()       {return ptr;}
       T const* get() const {return ptr;}
       T      * get()       {return ptr;}
    private:
       T* ptr;
    };
    

    clone sollte dann bei dir eine const-qualifizierte, virtuelle Funktion in der mother -Klasse sein, die jede abgeleitete Klasse überschreiben müsste.

    Wie man die Klone erzeugt und zerstört, könnte man noch parameterisieren.


Anmelden zum Antworten