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. |