CPtrList abgeleitet von list ?



  • hallo

    mir ist da diese Klasse in die Hände gekommen, und es stellt mir sich die Fragen.
    Wie kann ich erzwingen, daß die Klasse tatsächlich nur mit Zeigern als TYPE
    verwendet wird ?

    Ist die Implemetierung wenn mit Zeigern als TYPE gearbeitet wird denn überhaupt korrekt ?
    Denn die RemoveXXX-Methoden geben doch den Zeiger in der Liste nur frei, jedoch nicht den Speicher auf welchen der Zeiger in der Liste zeigt.

    Die Klasse kann so wie sie jetzt ist doch auch Objekte aufnehmen, für diesen
    Fall sehe ich die RemoveXXX-Metoden als korrekt.

    mfg
    RB

    template<class TYPE>
    class CPtrList : private std::list<TYPE>
    {
    public:
    	typedef typename std::list<TYPE>::iterator iterator;
    	typedef typename std::list<TYPE>::const_iterator const_iterator;
    	int GetCount() const {return size();}
    	void AddTail(const TYPE& x){push_back(x);}
    	void AddHead(const TYPE& x){push_front(x);}
    	void RemoveHead() {pop_front();}
    	void RemoveTail() {pop_back();}
    	void RemoveAll() {clear();}
    	TYPE& GetHead() {return front();}
    	TYPE GetHead() const {return front();}
    	TYPE& GetTail() {return back();}
    	TYPE GetTail() const {return back();}
    	iterator GetHeadPosition() { return begin();}
    	const_iterator GetHeadPosition() const { return begin();}
    	iterator GetTailPosition() { return back();}
    	TYPE& GetNext(iterator& pos) { return *pos++;}
    	const TYPE GetNext(const_iterator& pos) const{ return *pos++;}
    	TYPE& GetPrev(iterator& pos) { return *pos--;}
    	TYPE GetPrev(iterator& pos) const{ return *pos--;}
    	iterator Find(TYPE& x) { return std::find(begin(), end(), x);}
    	void RemoveAt(iterator& pos) { erase(pos);}
    	bool IteratorValid(const_iterator &iter) const
    	{
    		return iter != end();
    	}
    	bool IteratorValid(iterator &iter)
    	{
    		return iter != end();
    	}
    	iterator FindIndex(int iIndex)
    	{
    		iterator iter = begin();
    		int t = 0; while (t != iIndex) {iter++;t++;}
    		return iter;
    	}
    	const_iterator FindIndex(int iIndex) const
    	{
    		const_iterator iter = begin();
    		int t = 0; while (t != iIndex) {iter++;t++;}
    		return iter;
    	}
    	TYPE& GetAt(const iterator& pos) { return *pos;}
    	TYPE GetAt(const_iterator& pos) const{ return *pos;}
    };
    


  • template<class T>
    class list
    {
        //...
    };
    
    template<class T>
    class list<T*>
    {
        /...
    };
    
    //oder, wenn du ableiten willst:
    template<class T>
    class ptr_list;    //impl steht nirgends
    
    template<class T>
    class ptr_list<T*>
    {
        //...
    };
    


  • hier stand bloedsinn

    sorry 😞



  • hallo

    blödsinn macht auch sinn 😃 , @ness werds probieren ... Danke

    mfg
    RB



  • hallo,

    irgendwie gehts immer noch nicht so wie ich will,
    wenn ich nun

    template<class TYPE>
    class CPtrList : private std::list<TYPE*>
    {
    public:
    typedef typename std::list<TYPE*>::iterator iterator;
    typedef typename std::list<TYPE*>::const_iterator const_iterator
    ...

    schreibe und mit:

    CListPtr<CTest> listptr;
    CTest* test = new CTest();
    listptr.AddHead(test);

    teste bringt der Compiler die Meldung push_back() Konvertierung von
    class CTest* in const class CTest & nicht möglich

    Könnte sich jemand netter weise mal dran machen, mir mit einem kleinen Komplettbeispiel, was obige Klasse als Grundlage nimmt und nur die Methoden
    AddHead und RemoveHead implementiert.
    Wie gewollt, wird AddHead ein zeiger auf das Objekt übergeben, RemoveHead löscht den Zeiger und anschließend den Listeneintrag. Besten Dank im Voraus.

    mfg
    RB



  • hallo nochmal ...

    habe jetzt

    template<class TYPE>
    class CListPtr : private std::list<TYPE*>
    {
    public:
    	typedef typename std::list<TYPE*>::iterator iterator;
    	typedef typename std::list<TYPE*>::const_iterator const_iterator	
    	void AddHead(const TYPE* x)
    	{
    		push_front((TYPE*)x);
    	}
    	void RemoveHead() 
    	{ 
    		iterator iter = begin();
    		if( *iter != NULL )
    			delete *iter;
    		pop_front();
    	}
    ...
    

    und mit

    CListPtr<CTest> listptr;
    CTest* test = new CTest();
    listptr.AddHead(test);
    listptr.RemoveHead();

    das gewünschte Ziel erreicht. Gibts daran was auszusetzen oder zu korrigieren ?
    Negativ fällt mir der cast in AddHead schon mal auf, weiß aber nicht wie ich anders machen könnte. Der Parameter in AddHead soll ja den zeiger nicht ändern
    daher const TYPE* x, war vorher const TYPE& x.

    mfg
    RB



  • etwas gibt es schon zu bemängeln:

    if( *iter != NULL )
      delete *iter;
    

    wenn du damit prüfen willst, ob ein NULL-zeiger im listenelement gespeichert ist, dann kannst du das auch weglassen. bekommt delete NULL dann tut es einfach garnichts.

    wenn du damit prüfen willst, ob die liste nicht leer ist (was sinnvoller wäre), dann ist der code falsch und müßte

    if(!empty())
    {
      delete *begin();
      pop_front();
    }
    

    lauten.

    Dasselbe gilt natürlich auch für die funktion RemoveTail().

    übrigens gibts NULL in c++ nicht mehr. du solltest stattdessen besser 0 schreiben. außerdem ist (TYPE)* nicht sehr c++-mäßig. besser wäre const_cast<TYPE>*.

    aber um ehrlich zu sein, ich halte das ganze konzept einer liste, die die in ihr gespeicherten zeiger automatisch freigibt, für unglücklich. du kannst ja auch mit einer "normalen" stl-liste arbeiten, die die objekte auch selbst erzeugt. wenn du aber darauf bestehst, daß die objekte außerhalb der liste erzeugt werden, dann sollten sie auch dort gelöscht werden. nämlich außerhalb der liste und nicht von der listenklasse selbst.

    wenn man objekte nicht da löscht, wo man sie erzeugt, dann kann man sich damit ganz schön verhaspeln. und anschließend wundern sich die leut, wo die ganzen speicherlöcher herkommen. also ich würds nicht so machen 🙄



  • hallo,

    Danke für die Ratschläge, werds mal befolgen ...

    mfg
    rb



  • Konfusius schrieb:

    übrigens gibts NULL in c++ nicht mehr. du solltest stattdessen besser 0 schreiben. außerdem ist (TYPE)* nicht sehr c++-mäßig. besser wäre const_cast<TYPE>*.

    Ne, besser wäre es sich eine Möglichkeit zu überlegen ohne den Cast auszukommen.


Anmelden zum Antworten