ATL-COM-Objekt: wer zerstört es?



  • Hallo,
    möchte eine tree und eine item Klasse in ein ATL-COM-Objekt verpacken.
    Ich habe also eine Struktur dieser Art:

    tree
      |-item (root)
         |-item
           |-item
         ...
         |-item
           |-item
           |-item
    

    Für VB möchte ich diese bestehende Klasse kapseln. Der Einfachheit halber nenne ich die ATL-Klassen CTree und CItem, für die Interfaces ITree und IItem.

    Zum Exportieren brauche ich jetzt eine Instanz von CItem bzw CTree als ATL-COM-Objekte. CItem sollte wahrscheinlich einen Pointer auf das ursprüngliche item haben. Items sollen von VB nicht erstellt werden, sondern nur über die CTree-Klasse zurückgegeben werden.

    BSP:
    item *tree->getRoot()
    muß nach CTree gemappt werden.

    STDMETHODIMP CTree::getRoot(IItem **res)
    {
      //item ist der Verweis auf die C++-Klasse
      CItem *citem = new CItem(item);
      *res = citem;
      return S_OK;
    }
    

    Wer gibt jetzt dieses citem-Objekt wieder frei?
    Danke euch,
    Joe



  • Hast Du dir ja gleich was ganz kompliziertes rausgesucht 🙂

    Erstmal zu deiner Frage:

    (1) es fehlt noch

    (*res)->AddRef();
    

    (2) der client gbt es frei:
    if (!FAILED(pTree->getRoot(&pRoot)))
    {
    // ... use root
    pRoot->Release();
    }

    COM - Objekte sind referenzgezählt, es gibt feste Regeln, wer wann was addrefen und releasen mus. Das Release zählt den Referenzzähler ruter, und löscht das Objekt mit delete wenn er bei 0 Referenzen ankommt.

    Dein Tree bekommt aber ein mächtiges Problem, wenn jeder Item einen Rücklink auf seinen Parent (oder den Tree) haben soll: zirkuläre Referenzen. Gint aber iein paar möglichkeiten, das zu lösen.



  • Denke in dein fall ist ein 'weicher pointer' das beste, d.h deine items zählen den referenz counter der parents nicht hoch. Allerdings musst du dann auch noch was einbauen damit die items was mitebkommen wenn das parent stirbt, die refernz darauf also ungüligt wird.



  • peterchen schrieb:

    Hast Du dir ja gleich was ganz kompliziertes rausgesucht 🙂

    Jeder tut sein Bestes 🙂

    peterchen schrieb:

    (1) es fehlt noch

    (*res)->AddRef();
    

    ACK

    peterchen schrieb:

    (2) der client gbt es frei:
    if (!FAILED(pTree->getRoot(&pRoot)))
    {
    // ... use root
    pRoot->Release();
    }

    in meinem Fall ist der Client aber VB.
    Macht das jetzt

    Set root = Nothing
    

    automatisch? (Garbagecollecting?)

    peterchen schrieb:

    Dein Tree bekommt aber ein mächtiges Problem, wenn jeder Item einen Rücklink auf seinen Parent (oder den Tree) haben soll: zirkuläre Referenzen. Gint aber iein paar möglichkeiten, das zu lösen.

    Ach das ist kein Problem. Ich brauche den Baum nur zum lesen. Es werden keine Objekte eingefügt oder gelöscht. Und zirkuläre Referenzen gibt es auch nicht, es ist ein "echter" Baum ohne Kreise.

    CMatt schrieb:

    Denke in dein fall ist ein 'weicher pointer' das beste, d.h deine items zählen den referenz counter der parents nicht hoch. Allerdings musst du dann auch noch was einbauen damit die items was mitebkommen wenn das parent stirbt, die refernz darauf also ungüligt wird.

    Das ATL soll wirklich nur ein Interface sein. Bei Bedarf mach ich das Objekt, lese es aus und zerstöre es wieder. Der Tree bleibt erhalten. Es macht auch nichts aus, wenn das Item die Gültigkeit verliert, sobald der Baum weg ist.
    Ich will nur nicht den ganzen Baum nochmals schreiben.

    Joe



  • Set root = Nothing

    ja, aber keine GC, sondern eben referenzgezählt

    Ach das ist kein Problem

    Das Item-Objekt ist unabhängig vom Baum? (hast du ein glück 🙂 )



  • peterchen schrieb:

    Das Item-Objekt ist unabhängig vom Baum? (hast du ein glück 🙂 )

    Item hängt von Tree ab und CTree/ITree hält eine Instanz von Tree.

    Ich brauch das CItem/IItem nur, um auf die internen Items zuzugreifen. Sobald die CTree-Instanz zerstört wird, sind mir die anderen Referenzen auch egal.

    Danke für die Hilfe,
    Joe



  • Meine Frage war nicht ganz klar gestellt 🙂

    Hat der Item eine Referenz auf den Tree?

    (Wenn ja, mußt du sicherstellen, daß der interne Tree nicht zerstört wird, solange der Client noch referenzen auf die Items hat)



  • peterchen schrieb:

    Hat der Item eine Referenz auf den Tree?

    (Wenn ja, mußt du sicherstellen, daß der interne Tree nicht zerstört wird, solange der Client noch referenzen auf die Items hat)

    Keine Referenz auf den Tree

    Damit Du es ganz genau weißt, gib ich hier mal die Header an. 🙂
    Hier sind die vormals Item und Tree genannten Objekte als XMLItem bzw XMLTree bezeichnet (macht den Code leserlicher 🙂 )

    Außerdem arbeite ich mit einem kleinen Trick: Es gibt immer ein "leeres" XMLItem-Objekt als root. (d.h. Name und Value sind "", Path ist "/", ID = 0)
    Die root selbst hat einen einen NULL-Parent.

    Derweilen brauche ich den Baum dazu, Konfigurationen auszulesen und zu prüfen.
    Was ich damit mache:

    😉 Client Programm ruft Funktionen auf
    😉 Funktionsaufrufe werden als XML-String codiert (das mach ich gleich direkt)
    😉 XML-Strings werden über das Netzwerk verschickt
    😉 XML-Strings werden über das Netzwerk empfangen und ausgewertet mittels Tree

    Da ich die Pfade der einzelnen Informationen kenne, brauche ich auch keine Schemata. Wahrscheinlich halte ich mich nicht einmal genau an den XML-Standard, weil ich Attribute auch als normale Tags behandle. So ist bei mir

    <tag attribute="value"> <tag2/> </tag>
    dasselbe wie
    <tag>
      <attribute>value</attribute>
      <tag2/>
    </tag>
    
    class XMLItem  
    {
    	typedef std::vector<XMLItem*> XMLItemList;
    
    public:
    	XMLItem::XMLItem(std::string const& name, std::string const& value);
    	XMLItem::XMLItem(std::string const& name);
    
    	virtual ~XMLItem();
    	std::string getName() const;
    	std::string getValue() const;
    
    	void setValue(std::string const& value);
    	void addItem(XMLItem *xi);
    	void setParent(XMLItem *newParent);
    	XMLItem* getParent();
    	XMLItem* findItem(std::string path);
    	XMLItem* findNext(std::string path);
    	std::string getPath();
    	XMLItem* getChildren(int index) const;
    	int getChildrenCount() const;
    
    	int getID() const;
    
    	void print() const;
    	void printFull() const;
    
    private:
    	int getNewID();
    	int id_;
    	std::string name_;
    	std::string value_;
    	std::string path_;
    
    	XMLItem *parent_;
    	XMLItemList nodes_;
    
    };
    
    typedef std::vector<XMLItem*> XMLItemList;
    
    class XMLTree  
    {
    public:
    	XMLTree(std::string const& XML);
    	virtual ~XMLTree();
    
    	XMLItem *getRoot();
    
    private:
    	std::string trim(std::string str);
    	void   createFromString(std::string const& XML);
    	XMLItem *root_;
    };
    

    Danke nochmals an alle für die tatkräftige Unterstützung.
    Ihr seid super!

    Joe


Anmelden zum Antworten