Template Klasse in STL list



  • Hallo zusammen,

    ich habe ein Problem. Ich möchte eine selbst geschriebene Template Klasse in eine STL list einfügen. Jedoch bekomme ich immer den Compilerungsfehler:

    error C2664: 'std::list<_Ty>::push_back': Konvertierung des Parameters 1 von 'ref_ptr<NodeTyp>' in 'ref_ptr<NodeTyp> &' nicht möglich

    Hier der relevante Codeauschnitt:

    class MemoryManagementNode : public LCReferenced
    {
    	public:
    		~MemoryManagementNode(){cout << "MemoryNode destroyed" << endl;};
    };
    
    list<ref_ptr<LCReferenced>> nodeList;
    typedef list<ref_ptr<LCReferenced>>::iterator grIter;
    
    ................
    
    int main(int argc, char ** argv)
    {
    	ref_ptr<MemoryManagementNode> node =  new MemoryManagementNode;
    	node->print();
    	nodeList.push_back(node);
    .......
    

    Die ref_ptr Template Klasse sieht folgendermaßen aus:

    #ifndef REF_PTR_H
    #define REF_PTR_H
    
    #include "LCReferenced.h"
    
    using namespace std;
    
    template <typename NodeTyp>
    class __declspec(dllexport) ref_ptr
    {
    	//[---------------------------------------------------------------------------------------------]
    	//[ Constructors																				]
    	//[---------------------------------------------------------------------------------------------]
    	public:
    		ref_ptr(LCReferenced* nodePtr)
    		{
    			nodePointer = dynamic_cast<NodeTyp *>(nodePtr);
    			if(nodePtr != NULL) 
    			{
    				nodePointer->ref();
    			} else {
    				cout << "Initialization failure!" << endl;
    			}
    		};
    
    		ref_ptr():nodePointer(NULL){};
    
    		virtual ~ref_ptr()
    		{
    			if(nodePointer != NULL) 
    			{
    				nodePointer->unref();
    				nodePointer = NULL;
    			}
    		};
    	//[---------------------------------------------------------------------------------------------]
    	//[ Variables																					]
    	//[---------------------------------------------------------------------------------------------]
    	protected:
    		NodeTyp* nodePointer;
    
    	//[---------------------------------------------------------------------------------------------]
    	//[ Functions																					]
    	//[---------------------------------------------------------------------------------------------]
    	public:
    		NodeTyp* get() const{ return nodePointer; };
    
    		bool valid() const
    		{
    			if(nodePointer) return true;
    			return false;
    		};
    
    		NodeTyp &operator=(const LCReferenced* nodePtr)
    		{
    			if(nodePtr != NULL) 
    			{
    				if(nodePointer) nodePointer->unref();
    				nodePointer = nodePtr;
    				nodePointer->ref();
    			} else {
    				cout << "Assignment faild!" << endl;
    			}
    			return *this;
    		};
    
    		NodeTyp &operator=(const NodeTyp& nodePtr)
    		{
    			if(nodePtr.get() != NULL) 
    			{
    				if(nodePointer) nodePointer->unref();
    				nodePointer = nodePtr.get();
    				nodePointer->ref();
    			} else {
    				cout << "Assignment faild!" << endl;
    			}
    			return *this;
    		};
    
    		NodeTyp* operator->() const { return nodePointer; };
    		bool operator==(const NodeTyp& nodePtr)	{ return (nodePointer == nodePtr.get()); };
    		bool operator==(const LCReferenced* nodePtr){ return (nodePointer == nodePtr); };
    };
    
    #endif
    

    Die LCReferenced Klasse besitzt folgendes Aussehen:

    class __declspec(dllexport) LCReferenced
    {
    	//[---------------------------------------------------------------------------------------------]
    	//[ Constructors																				]
    	//[---------------------------------------------------------------------------------------------]
    	public:
    		LCReferenced();
    	protected:
    		virtual ~LCReferenced();
    
    	//[---------------------------------------------------------------------------------------------]
    	//[ Variables																					]
    	//[---------------------------------------------------------------------------------------------]
    	public:
    
    	protected:
    		int refCounter;
    	private:	
    
    	//[---------------------------------------------------------------------------------------------]
    	//[ Functions																					]
    	//[---------------------------------------------------------------------------------------------]
    	public:
    		void ref();
    		void unref();
    
    	private:
    
    	protected:
    
    };
    

    Hat jemand eine Idee?

    Grüsse Nekoto



  • list<ref_ptr<LCReferenced>> nodeList;
    typedef list<ref_ptr<LCReferenced>>::iterator grIter;
    

    geht (noch) nicht, mach list<ref_ptr<LCReferenced> > , sonst wird es als rechts-shift interpretiert.



  • Du willst einen ref_ptr<MemoryManagementNode> in eine Liste von ref_ptr<LCReferenced> packen - selbst wenn die verzeigerten Klassen miteinander verwandt sind, sind die ref_ptr<> Instanziierungen unabhängig voneinander - und müssten zur Not manuell ineinander umgewandelt werden*.

    Außerdem: Was bringt es denn, die Klasse als Template zu definieren, wenn du letztendlich doch nur LCReferenced-Abkömmlinge damit verwalten willst?

    * sprich: du benötigst einen Template-Copy-Ctor



  • Die ref_ptr Template Klasse habe ich geschrieben um verschiedene Abkömmlinge von LCReferenced zu verwalten. Dabei wollte ich nicht immer ein downcast machen müssen um auf die jeweiligen Elementfunktionen der Kindklassen von LCReferenced zugreifen zu können. Prinzipiell realisert mir das ref_ptr Template eine Speicherverwaltung auf die Elemente die ich mit new ... dem entsprechenden ref_ptr Element zuweise.

    Die STL list möchte ich zur Verwaltung der Kind-Elemente in einer Baumstruktur verwenden (Composite Pattern).



  • Habe mal Deinen Rat befolgt CStoll und aus:

    list<ref_ptr<MemoryManagementNode>> nodeList;
    typedef list<ref_ptr<MemoryManagementNode>>::iterator grIter;
    

    gemacht. Jetzt gibt es keine Kompillierungsfehler mehr. Wenn ich aber nun folgendes versuche:

    grIter tempIter = find(nodeList.begin(), nodeList.end(), node);
    

    kommt folgende Fehlermeldung:

    algorithm(40) : error C2679: Binärer Operator '==': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'const ref_ptr<NodeTyp>' akzeptiert (oder keine geeignete Konvertierung möglich)

    Hast Du dazu noch einen Vorschlag?

    Grüsse Nekoto



  • Nekoto schrieb:

    Habe mal Deinen Rat befolgt CStoll und aus:

    list<ref_ptr<MemoryManagementNode>> nodeList;
    typedef list<ref_ptr<MemoryManagementNode>>::iterator grIter;
    

    gemacht. Jetzt gibt es keine Kompillierungsfehler mehr. Wenn ich aber nun folgendes versuche:

    grIter tempIter = find(nodeList.begin(), nodeList.end(), node);
    

    kommt folgende Fehlermeldung:

    algorithm(40) : error C2679: Binärer Operator '==': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'const ref_ptr<NodeTyp>' akzeptiert (oder keine geeignete Konvertierung möglich)

    Hast Du dazu noch einen Vorschlag?

    Grüsse Nekoto

    Ergänzung zur Fehlermeldung:

    with
    [
    NodeTyp=MemoryManagementNode
    ]



  • Nunja, fuer find muss er die Elemente aus der Liste mit dem uebergebenen Argument (bei dir: node) vergleichen. Wenn du fuer den entsprechenden Typen (hier: ref_ptr<MemoryManagementNode>) keinen operator==() definiert hast ist das nicht moeglich.


  • Mod

    CStoll schrieb:

    * sprich: du benötigst einen Template-Copy-Ctor

    So etwas gibt es nicht. Allerdings fehlt dieser Klasse zusätzlich ein richtiger Copy-ctor. * und != sollten ebenfalls überladen werden. Zudem enthält der Construktor, der einen normalen Zeiger nimmt ein Speicherleck, falls der cast fehlschlägt. Der entsprechende Zuweisungsoperator dürfte überflüssig sein. Der Copy-Zuweisungsoperator genügt nicht den Assignable-Containervoraussetzungen der Standardbibliothek. Die Klasse dürfte für Verberung nicht geeignet sein - ein virtueller Destruktor ist daher unnötig und kostet nur unnötig Speicherplatz (und nutze private statt protected).



  • camper schrieb:

    Der Copy-Zuweisungsoperator genügt nicht den Assignable-Containervoraussetzungen der Standardbibliothek.

    Was meinst Du genau damit? Steh gerade auf dem Schlauch.


  • Mod

    Table 64—Assignable requirements
    expression      return type           post-condition
    t = u           T&                    t is equivalent to u
    
    ref_ptr<MemoryManagementNode> node1 =  new MemoryManagementNode;
    ref_ptr<MemoryManagementNode> node2;
    node1 = node2;
    assert( node1 == node2 ); // ups
    

    und

    ref_ptr<MemoryManagementNode> node =  new MemoryManagementNode;
    node = node; // boom
    


  • @ camper Vielen Dank! Sehr gute Ausführung.

    @ all: Vielen Dank für die schnellen und hilfreichen Antworten!

    Grüsse Nekoto


Anmelden zum Antworten