Zeiger auf Objekt trotz überladenem &-op
-
Folgendes Beispiel:
class A { }; //smart-pointer-Implementierung template <typename T> class Ptr { public: T** operator&(); //... }; int main() { Ptr<A> ptr; Ptr<A>* pptr(&ptr); //geht nicht, da &ptr keinen Ptr<A>* liefert return 0; }
Wie komm ich an die Adresse von ptr ran?
Hintergrund:
Bei COM gibt es so ne Art Smartpointer für jedes Objekt. Bei diesem ist der &-Op wie oben überladen. Zugleich hab ich Funktionen, die einen Zeiger auf einen solchen Pointer wollen.
Momentan krieg ichs nur hin, wenn ich die Smart-Pointer selbst mit new dynamisch anlege.
-
Aehmmmmmm ?
Ich nehm mal an, Du sprichst von CComPtr und CComQIPtr ???Zugleich hab ich Funktionen, die einen Zeiger auf einen solchen Pointer wollen.
Diese Funktionen, die einen Pointer auf CComQIPtr<IMyInterface> verlangen, sind selbst geschrieben ??? Denk ich zumindest, ich kenne keine aus der ATL die sowas verlangt
Waere auch vom Konzept her irgendwie ... daneben. CComPtr und CComQIPtr sind reine Wrapperklassen, also Hilfsklassen. Zeiger von denen durch Funktionsparamater zu schleussen macht keinen Sinn, meiner Meinung nach. Nimm lieber das als Functionsparameter was du wirklich willst ... naemlich die Zeiger auf deine Schnittstelle (IMyInterface ) oder (IMyInterface*).
Benutze die Smartpointer nur local .... also Schnittstellenzteiger bekommen, mit nem Smartpointer uebernehmen (Attach), mittels Wrapperfunktionen die Schnittstelle bearbeiten, Schnittstellenzeiger wieder freigeben (Detach), Schnittstellenzeiger zur weiterverarbeitung weitergeben ....
Und der naechsten funktion uebernimmst den Schnittstellenzeiger wieder mit nem Smartpointer ... usw .....Was spricht dagegen ? Performance ?
Was willst du genau machen ???
Ich hab noch keinen Fall gehabt, wo ich es gebraucht haette ....
Aber wenn Du es unbedingt brauchst ..... Mach dir doch ne eigene Smartpointer-Klasse (oder Template) .... , leite sie von CComQIPtr ab .... und Implementier zusaetzlich ne Function, die Dir die Adresse ( return this ) zurueckgibt ....Ciao ...
[ Dieser Beitrag wurde am 30.04.2003 um 09:56 Uhr von RHBaum editiert. ]
-
Original erstellt von <kartoffelsack>:
**Folgendes Beispiel:class A { }; //smart-pointer-Implementierung template <typename T> class Ptr { public: T** operator&(); //... }; int main() { Ptr<A> ptr; Ptr<A>* pptr(&ptr); //geht nicht, da &ptr keinen Ptr<A>* liefert return 0; }
**
Klar! "&ptr" liefert "A**"
**
Wie komm ich an die Adresse von ptr ran?
**Dafür gibt es doch viele Möglichkeiten. Wie wäre es einfach eine Methode
Ptr<T>* GetAddr() const { return this; }
in die Klasse einzufügen? Allerdings würde ich eher den "&"-Operator dabei belassen, wofür er auch gedacht ist und zwar für die Rückgabe der Adresse. Du kannst mal ausprobieren, ob man den "&"-Operator auch mehrfach überladen kann, sodass der Compiler anhand des Rückgabewertes entscheiden kann, welche Implementierung er zu verwenden hat. Aber ich glaube, dass dies bei Operatoren nicht geht. Deshalb würde ich erst gar nicht den "&"-Operator überladen und Deine spezielle Implementierung in eine Methode mit sprechenden Namen packen.
-
nope, hab sie nicht selber geschrieben.
Das ist in den vom C-Builder erzeugten TLB-Klassen so (das entspricht etwa der ATL, so wie ich das sehe).
Die ganzen Get-Funktionen haben keine Ptr-Objekt als Rückgabewert sondern erhalten einen Zeiger welcher dann auf das Objekt zeigt
z.B.:
// *********************************************************************// // Schnittstelle: IGeographicCoordinateSystem // Flags: (256) OleAutomation // GUID: {40870D80-1DD2-11B2-BF4C-08002022F573} // *********************************************************************// interface IGeographicCoordinateSystem : public Esricore_tlb::ISpatialReference { public: // [1610809344] The usage notes of this geographic coordinate system. virtual HRESULT STDMETHODCALLTYPE get_Usage(BSTR* Usage/*[out,retval]*/) = 0; // [1610809345] The horizontal datum of this geographic coordinate system. virtual HRESULT STDMETHODCALLTYPE get_Datum(Esricore_tlb::IDatumPtr* Datum/*[out,retval]*/) = 0; // [1610809346] The prime meridian of this geographic coordinate system. virtual HRESULT STDMETHODCALLTYPE get_PrimeMeridian(Esricore_tlb::IPrimeMeridianPtr* prime/*[out,retval]*/) = 0; // [1610809347] The angular unit of this geographic coordinate system. virtual HRESULT STDMETHODCALLTYPE get_CoordinateUnit(Esricore_tlb::IAngularUnitPtr* CoordinateUnit/*[out,retval]*/) = 0; };
Jetzt muss ich so aufrufen:
std::auto_ptr<IAngularUnitPtr> apAnUPtr(new IAngularUnitPtr); GeoCoordSystemPtr->get_CoordinateUnit(apAnUPtr.get());
dabei gibst keinen Grund das die AngularUnit dynamsisch angelegt wird und es macht den Code nicht gerade schöner.
An sich würd ichs gern so machen:
IAngularUnitPtr AnUPtr; GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);
Wischmop2s Lösung wär die äußerste Notlösung. Ich müsste dann die die Klasse TComInterface, der Template-Klasse für die ganzen Ptr-Klassen ändern. Das würd ich nur sehr ungern machen, weil das sind Bibs, die beim Compiler dabei sind.
Gehts nicht irgendwie von außen?[ Dieser Beitrag wurde am 30.04.2003 um 10:19 Uhr von kartoffelsack editiert. ]
-
hab ich doch schonmal irgendwo gesehen ...
template <typename T> T* addressof(T& v) { return reinterpret_cast<T*>( &const_cast<char&>(reinterpret_cast<const volatile char &>(v))); }
-
Besten dank, werde gleich ausprobieren (nach dem Mittagsessen )
-
alternativ kannst du auch sowas in der art machen (wenn du unbedingt den & operator behalten willst):
class A { int *x; public: A () : x(new int(50)) {} ~A () { delete x; } //der trick: ein rückgabetyp spielt bei der auflösung von überladenen //funkionen keine rolle, nur bei den konvertierungsoperatoren. //also einfach einen dummy mit 2 verschiedenen konvert.ops. zurückgeben, //und das war's; class dummy { int *i; A *a; public: dummy (int *i_, A *a_) : i(i_), a(a_) {} operator int * () const { return i; } operator A * () const { return a; } }; //der overhead: es werden nun eben statt einer adresse immer 2 zurückgegeben... dummy operator & () { return dummy(x, this); } }; int main () { A a; int *i = &a; A *aptr = &a; }
-
Aehmmmm Agypten ???
Esricore_tlb::IDatumPtr* Datum
Kanns mal die deklaration von Esricore_tlb::IDatumPtr posten ???
Ich glaub ned, das das ne Smartpointerklasse ist ... sondern ich denke eher das es nen roher Schnittstellenzeiger ist ....ich vermute Esricore_tlb::IDatumPtr = Esricore_tlb::IDatum *
und IDatum ist nen normales COM-InterfaceWarum, erstens wurd ich Smartpointerklassen nie mit IXyz betiteln .... (weil irrefuehrend, siehe grad an mir )
und zweitens macht es ne klassenBiblio wirklich nicht unbedingt benutzerfreundlich, wenn man Zeiger auf nen Objekt verlangt, dem Objekt aber den Adressoperator ueberlaed .... und was vollkommen anderes zurueckgeben laesstP.S.
Zumindest bei der ATL (CComQIPtr, CComPtr) ist der & Operator so ueberladen, dass er nicht this, sondern die Addresse des Interface-Zeigers(T **) zurueckgibt ... damit man grad diese Smartpointer ohne umstaendliche konvertierungen mit den COM-Funktionen verwenden kann ....
und die COM functionen verlangen immer nur Schnittstellenzeiger ....std::auto_ptr<IAngularUnitPtr> apAnUPtr(new IAngularUnitPtr); GeoCoordSystemPtr->get_CoordinateUnit(apAnUPtr.get());
Uahm .... new auf nen Schnittstellenzeiger .... poese poese poese
Merke! Com-Objekte laesst man erzeugen, und erzeugt man nie selber !!!
entweder ein anderes Com-Object ist creator (IGeoCoordSystem fuer IAngularUnit), oder man laesst es das BS erzeugen .... die Zauberfunktion dazu heisst CoCreateInstance.
Sicher das das funktioniert ?IAngularUnitPtr AnUPtr; GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);
Was geht daran ned ? Fehlermeldung? welche ?
besser waere so:IAngularUnitPtr AnUPtr = NULL; HRESULT hr = GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);
keine Ahnung ob es HRESULT in VCB gibt ... zumindest muesste nach erfolg von CoordinateUnit() in AnUPtr ein Wert stehen und hr muesste aud SUCCESS stehen !
Alternativ muesse auch gehenIAngularUnit * AnUPtr = NULL; HRESULT hr = GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);
und das correct mit Smartpointer Umgesetzt !
std::auto_ptr<IAngularUnit> p_AngularUnit; // braucht man ned mit Null initialisieren HRESULT hr = GeoCoordSystemPtr->get_CoordinateUnit(&p_AngularUnit);
std::auto_ptr<IAngularUnitPtr>
Warum nen Smarpointer mit einem Zeiger auf Schnittstelle typisiert ???
der AdressOperator wuerde IAngularUnitPtr ** zurueckgeben ... was aufgeloest IAngularUnit *** ist! Macht das Sinn ?Ciao ...
[ Dieser Beitrag wurde am 30.04.2003 um 15:36 Uhr von RHBaum editiert. ]
-
@RHBaum Leider bin ich mit COM noch nicht ganz so firm (genauer gesagt beschäftige ich mich erst seit Montag nachmittag damit).
Wenn ich also Schmarrn rede, nimms mir nicht übel.
@Mods könnt das ggf nach rund-um verschieben. Mein c++-Problem ist mit boost::addressof gelöst.
Esricore_tlb::IDatumPtr* Datum
Kanns mal die deklaration von Esricore_tlb::IDatumPtr posten ???
Ich glaub ned, das das ne Smartpointerklasse ist ... sondern ich denke eher das es nen roher Schnittstellenzeiger ist ....
ich vermute Esricore_tlb::IDatumPtr = Esricore_tlb::IDatum *
und IDatum ist nen normales COM-Interfaceinterface DECLSPEC_UUID("{53004780-1DD2-11B2-BF4B-08002022F573}") IDatum;
typedef TComInterface<IDatum, &IID_IDatum> IDatumPtr;IDatum ist das Interface, IDatumPtr ist der Smart-Pointer, der das Objekt (mit dem Interface) hält. Das Objekt selber bekomm ich direkt doch sowieso nicht zu sehen.
Jedenfalls gibt es in der vom C++Builder erzeugten esriCore_TLB.h immer einen Ptr, ein Interface und eine Co-Klasse. Also keine rohen schnittstellenzeiger
Warum, erstens wurd ich Smartpointerklassen nie mit IXyz betiteln .... (weil irrefuehrend, siehe grad an mir )
und zweitens macht es ne klassenBiblio wirklich nicht unbedingt benutzerfreundlich, wenn man Zeiger auf nen Objekt verlangt, dem Objekt aber den Adressoperator ueberlaed .... und was vollkommen anderes zurueckgeben laesstDas ist der Smartpointer der zum Interface gehört, oder? Naja, egal. Ich habs nicht gemacht, wie gesagt der Code wird generiert und weil ich keine Ahnung von COM hab, kann ich auch keine Vergleiche ziehen.
Zumindest bei der ATL (CComQIPtr, CComPtr) ist der & Operator so ueberladen, dass er nicht this, sondern die Addresse des Interface-Zeigers(T **) zurueckgibt
Genauso bei mir hier.
damit man grad diese Smartpointer ohne umstaendliche konvertierungen mit den COM-Funktionen verwenden kann ....
und die COM functionen verlangen immer nur Schnittstellenzeiger ....Naja, irgendwie ist das alles ein bisschen komisch.
Wenn ne Funktion in meinem Header-File so deklariert ist
virtual HRESULT STDMETHODCALLTYPE get_CoordinateUnit(Esricore_tlb::IAngularUnitPtr* CoordinateUnit/[out,retval]/) = 0;
Dann steht dazu in der Doku
-Visual Basic 6.0- Property CoordinateUnit As IAngularUnit -Visual Basic .NET- Public Read Only Property CoordinateUnit As IAngularUnit -C#- public IAngularUnit CoordinateUnit {get;} -C++- public: __property IAngularUnit get_CoordinateUnit();
Das ist durchgängig so. Meine Funktionen schreiben das was hier als Rückgabeparameter definiert ist in das übergebene Zeigerobjekt und geben ein HRESULT zurück. Das is zwar ok so, aber es wundert mich, wie diese Abweichung Doku - Code zustandekommt (aber ok, meine Header werden ja von C-Builder generiert, eine anderer Compiler generiert das vielleicht anders). Was ich aber noch komischer finde. Das Problem mit dem überladenen &-Op kann nicht nur ich haben ...
Uahm .... new auf nen Schnittstellenzeiger .... poese poese poese
Merke! Com-Objekte laesst man erzeugen, und erzeugt man nie selber !!!Ich erzeuge aber doch nicht das COM-Objekt, sondern das Zeigerobjekt, welches dann das COM-Objekt, das mir irgendjemand von der COM-Seite generiert verwaltet. Also wenn mich meine C++-Kenntnisse nicht ganz täuschen muss ich das so machen. Weil die Ptr-Klasse kann das COM-Objekt, das sie verwaltet zerstören. Sie kann sich aber nicht selber zerstören.
IAngularUnitPtr AnUPtr;
GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);
Was geht daran ned ? Fehlermeldung? welche ?Das geht net, weil &AnUPtr die Adresse des rohen Interface-Zeigers T ** zurückgiebt, die Funktion aber die Adresse der Ptr-Klasse haben will (die sich ja dann um den rohen Interface-Zeiger kümmern soll).
IAngularUnit * AnUPtr = NULL;
HRESULT hr = GeoCoordSystemPtr->get_CoordinateUnit(&AnUPtr);Ich arbeite aber doch nicht mit rohen Zeigern auf das Interface sondern mit den Ptr-Klassen.
Wie würdest Du in Deinem Beispiel AnUPtr freigeben. Wer weiß ob get_CoordinteUnit das new benutzt, das es benutzen sollte, damit mein delete geht.Warum nen Smarpointer mit einem Zeiger auf Schnittstelle typisiert ???
der AdressOperator wuerde IAngularUnitPtr ** zurueckgeben ... was aufgeloest IAngularUnit *** ist! Macht das Sinn ?Ja, macht es. Die Ptr-Klasse verhält sich wie ein Zeiger. Außerdem wär es schlechter Stil, wenn eine Funktion was ne Resource belegt, das zurückgibt und sagt, "da, kümmer Du Dich drum".
Also bei meiner TLB hier ist das so:
Es gibt eine Ptr-Klasse für jedes Interface. Das kümmert sich um die Verwaltunge der Interface-Objekte (Referenzzähler etc). Um die Speicherverwaltung der Ptr-Klassen muss aber ich mich kümmern.Mit dem adressof geht das ganze jetzt so
IAngularUnitPtr AnUPtr;
GeoCoordSystemPtr->get_CoordinateUnit(boost::addressof(AnUPtr));
AnUPtr->get_WasAuchImmer(...);D.h. ich brauch nirgends mit dynamsichem Speicher oder so rumtun.
[ Dieser Beitrag wurde am 30.04.2003 um 18:17 Uhr von kartoffelsack editiert. ]
-
@Mods könnt das ggf nach rund-um verschieben
Aber sicher doch.