Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » FAQ C / C++ (ANSI-Standard) » Memoryleaks durch kluge Zeiger bekämpfen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
18.12.2003, 11:51 Uhr
virtual
Sexiest Bit alive
(Operator)


In C++ sind Memoryleaks nach wie vor eine der Hauptfehlerquellen. Mancher schaut aus diesem Grund neidisch in die Javawelt, wo Java selbst dafür sorgt, daß Objekte, die nicht mehr genutzt werden, automatisch abgeräumt werden ("Garbage Collection").
Mit dem Template auto_ptr bietet die STL zwar in Ansätzen soetwa wie "halbschlaue" Zeiger, die jedoch mit Vorsicht zu geniessen sind:

C++:
void f()
{
    int* q = new int;
    std::auto_ptr<int> p = new int;
    ...
    *q = 4711;
    *p = 4712;
    ...
    /* Am Ende der Routne werden p und q beide gelöscht. q ist ein normaler Zeiger, deshalb
       wäre hier ein "delete q" notwendig; p ist ein auto_ptr der einen Destructor hat.
       Dieser Destructor ist schlau genug, das delete automatisch zu machen. */

    delete q;
}


Das eigentliche Problem mit den auto_ptr ist, daß sie nach dem "Strict OwnerShip" Prinzip funktionieren: der Zeiger, der in p enthalten ist, kann nur einer auto_ptr instanz gehören:

C++:
void g()
{
    std::auto_ptr<int> p = new int;
    std::auto_ptr<int> r = p;
    ...
}


Nachdem das p dem r zugewiesen wird, gehört der speicher, der ursprünglich dem p zugewiesen wurde nun dem r und p zeigt nunmehr nirgendwohin.

Um sowas hinzukrigen, wie in Java, braucht man wirklich kluge Pointer, also Smart Pointer:

C++:
void h()
{
    smart_ptr<int> p = new int;
    smart_ptr<int> r = p;
    ...
    *r = 4711;
    std::cout<<(*p)<<std::endl; // Gibt auch 4711 aus!
    ...
}


Die richtige Implementation von smart_ptr vorausgsetzt sollten nun p und r beide auf den gleichen Speicherbereich zeigen und gleichzeitig dafür sorgen, daß - sobald der Speicher nicht mehr referenziert wird - der Speicher auch freigegeben wird. Das folgende Template erlaubt genau dies. Zu benachten ist, daß man als Templateparameter beliebige Klassen oder primitive Typen verwenden kann:

C++:
class ComplexClass
{
    ...
public:
    void aMethod();
}
...
void i()
{
    smart_ptr<ComplexClass> p = new ComplexClass;
    
    p->aMethod();
}


Hier das Template:

C++:
#ifndef SMARTPTR_H_INCLUDED
#define SMARTPTR_H_INCLUDED


template<typename T>
class smart_ptr
{
//  === TYPES =================================================================
private:
    typedef T value_type;       //!< Object type
    typedef T* pointer_type;    //!< Pointer type

    /** share_t.
     * This helper class is a pointer combined with a reference counter.
     * add_ref increase the reference counter; rem_ref removes it. When
     * reference count is 0, the object is destructed.
     */

    class share_t
    {
    //  --- ATTRIBITUTES ------------------------------------------------------
    private:
        pointer_type data;                      //!< Data
        int refs;                               //!< Number of references
    //  --- METHODS -----------------------------------------------------------
    private:
        //! Copy is forbidden
        share_t(const share_t&);

        // Assignment ist forbidden
        share_t& operator = (const share_t&);

    protected:
        //! Destructor, only internal destruction allowed.
        ~share_t() { delete data; }
    public:
        //! Constructor
        share_t(pointer_type data_) : data(data_), refs(1) {}

        // Add a reference
        void add_ref() { ++refs; }

        // Rem a references
        void rem_ref() { if (!(--refs)) delete this;}

        //! Access data
        pointer_type get() const { return data; }

        //! Check if shared
        bool is_shared() const { return refs > 1; }
    };

//  === ATTRIBUTES ============================================================
private:
    share_t* data;                              //!< Associated share

//  === METHODS ===============================================================
public:
    //! Standard constructor - create an smart pointer for nativ pointer
    smart_ptr(pointer_type data_) :data(new share_t(data_)) { }

    //! Copy constructor
    smart_ptr(const smart_ptr& source) :data(source.data) { data->add_ref(); }

    //! Destructor
    ~smart_ptr() { data->rem_ref(); }

    //! Assignment from other smart_ptr
    smart_ptr& operator = (const smart_ptr& other)
        {
            other.data->add_ref();
            data->rem_ref();
            data = other.data;
            return *this;
        }

    //! Assignment from plain pointer
    smart_ptr& operator = (pointer_type data_)
        {
            share_t* new_data = new share_t(data_);
            data->rem_ref();
            data = new_data;
            return *this;
        }

    //! Get pointer
    pointer_type operator -> () const { return data->get(); }

    //! Dereference pointer
    value_type& operator * () const { return *(data->get()); }

    //! Get Pointer
    pointer_type get() const { return data->get(); }

    //! Check for null pointer
    bool is_null() const { return data->get(); }

    //! Check, if shared
    bool is_shared() const { return data->is_shared(); }

    //! Check if equal
    bool operator == (const smart_ptr& other) const { return other.data == data; }

    //! Check if not equal
    bool operator != (const smart_ptr& other) const { return other.data != data; }

};

#endif


PS: ggf. vorhandene Fehler bitte Melden, ist nur so dahin gesaut ;)


Bearbeitung von virtual:
Danke an @(un)wissender für die Hinweise!

--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 27.07.2004 um 14:23 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ FAQ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: