shared_ptr casten
-
Nee, leider nicht,
die Situation ist, dass ich auf keiner Seite die Information zu beiden Typen zur Compile-Zeit habe. Ich kann wissen, dass auf der anderen Seite irgendein shared_ptr steht, und ich auf dieser Seite einen haben möchte, vielleicht mit anderem Typ. Ich habe zudem Maschinerie (In Form eines cast-graphs), die den Cast für den angezeigten Typ umsetzen kann oder aber auch nicht. Stellt euch das so vor, dass ich das zwischendurch durch ein void* pressen muss. Aber die casts, die stattfinden, sind bei Benutzung im spezifizierten Rahmen "sicher".
Wenn das nicht geht, muss ich dieselbe Maschinerie benutzen, um shared_ptr<T>'s ineinander zu konvertieren (plus Benutzung von boost::any oder einem äquivalent, weil dann ja zwischendurch echte Wert-Typen benötigt werden), wenn es ginge, bräuchte ich nichts zusätzliches zu tun.
-
Ich verstehe nicht ganz, warum du nicht dynamic_pointer_cast oder static_pointer_cast benutzen kannst.
Aber so würde es auch gehen:
U* convert_somehow(T*); int main() { shared_ptr<T> p1 = ...; shared_ptr<U> p2 (p1,convert_somehow(p1.get())); }Hier teilen sich p1 und p2 denselben Deleter und dieselben Referenzzähler.
-
Ganz genau erklärt (mit den Konsequenzen, die ich aber schon beschrieb):
Ich habe sozusage Type-Erased Typen hier und das bezieht sich wiedermal auf meine luabind-Anpassungen.
Ich habe einen opaken Typ, den ich darum bitten kann, einen Wert mit als void* verkappten Typ mit gewisser ID (ein integer-Wert, der bei Programmstart erzeugt wird) zurückzuliefern. Hinter der Fassade wird das mit einem Netzwerk von Casts gemacht, die zur Compile-Zeit generiert werden. Das dient dazu, dass man alle Klassen, die registriert werden und zu denen man die Beziehungen angibt, ineinander konvertieren kann (ausschließlich wenn Zeiger und Referenzen verlangt werden, Slicing möchte ich nicht noch unterstützen), ohne dass eine kombinatorische Explosion zu befürchten ist.
Nun wird zur Laufzeit eine C++-Funktion aufgerufen und während die Signatur mit den Parametern gematcht wird, versucht der Matcher das opake Argument anzuweisen, einen Zeiger vom gewünschten Typ zu liefern.
Für smart pointer existiert spezieller Code, der den smart pointer bei der Betrachtung sozusagen "überspringt" und direkt mit den von den Zeigern angezeigten Objekten arbeitet. Ich kann also einen Zeiger auf ein implizit gecastetes Objekt erhalten und weiß, dass dieses Objekt durch einen smart-pointer gehalten wird, aber ich habe keine Möglichkeit einen neuen smart-pointer zusammenzusetzen, weil ich dafür wahrscheinlich explizit die Implementierungs-Interna verwenden müsste (also den Deleter und den Count-Holder mit rüberreichen, von denen ich ausgehe, dass sie an oberster Ebene nicht vom Typ des Zeigers abhängen).
-
Und meine Fallback-Lösung ist jetzt, für smart pointer ebenfalls casts im Cast-Graph zu hinterlegen. Da müsste dann der Benutzer gegenenenfalls etwas mithelfen und ansagen, ob und mit welchen smart-pointern so hantiert wird.
-
Wenn ich das richtig verstanden habe, verliert er irgendwann die Information, dass das Objekt bereits in einen
shared_ptrverpackt ist.Darfst/kannst du
Tanfassen? Du kannstTvonenable_shared_from_thiserben lassen und den Reference Counter nachTverschieben.
-
Halllo Doc,
ich möchte nicht vorschreiben, dass man davon ableitet, aber danke dass Du's erwähnst, da hatte ich noch gar nicht dran gedacht, einen Spezialcase dafür, wenn das möglich ist, werde ich auf jeden Fall vorsehen!
-
Und die Information, dass ein shared_pointer auf der anderen Seite ist, habe ich schon, aber ich habe zur Compile-Zeit nicht die Typ-Information von beiden Seiten, sodass ich "einfach" static_pointer_cast oder dynamic_pointer_cast verwenden könnte (von lua aus kann man ja mit allen möglichen Argumenten die Funktion aufrufen).
-
@decimad
krümelkacker hat dir doch schon ne Lösung geschrieben. Wo ist denn bei der das Problem?Anstatt das (undokumentierte) Counter-Objekt abzuspeichern kannst du dann einfach nen
shared_ptr<void>abspeichern. (Oder sogar nenweak_ptr<void>).
Aus diesem plus einemT*kannst du dir dann jederzeit wieder nenshared_ptr<T>basteln der das selbe Counter-Objekt (inklusive Deleter) verwendet wie der "originale"shared_ptr.Das kann man z.B. auch dazu verwenden
shared_ptrauf Member von Objekten zu erzeugen. Also quasi sowas:shared_ptr<MyStruct> p = ...; shared_ptr<int> p2(p, &(p->myIntMember)); // Zeigt auf das "myIntMember" in *p und hält gleichzeitig *p am Leben
-
Moah, mea culpa, da hätte ich besser recherchieren müssen, krümel's Vorschlag habe ich einfach missverstanden. Praktisch genau das habe ich ja gesucht von Anfang an, ich wollte ja den share counter wiederverwenden und etwas anderes reintun
Moah... Es tut mir Leid eure Zeit vergeudet zu haben mit ellenlangem Text, ich hatte nie im Traum gewagt zu glauben, dass die shared_ptr-Entwickler an so einen Spezialfall gedacht haben... Da brauche ich nur für die unterstützten smart-pointer per traits einen Repräsentanten zu definieren (eben std::shared_ptr<void> und habe auch einen spezifischen Typ, nach dem ich Fragen kann. Genialst! Danke euch!
-
Hehe.
> krümel's Vorschlag habe ich einfach missverstanden
Das (oder dass du den Beitrag übersehen hast) hab' ich fast schon vermutet, daher hab' ich nochmal nachgefragt.Es ist eben kein so spezieller Spezialfall, und daher wird das auch unterstützt. Gerade die "inner Pointer" (also Zeiger auf ein Member) braucht man öfters. Bzw. wenn man "Casts" Marke Eigenbau wie z.B.
IUnknown::QueryInterfaceverwenden will braucht man es auch. Und das kommt durchaus nicht SO selten vor.ps: Hier der passende "cppreference" Link:
http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
- Constructs a shared_ptr which shares ownership information with r, but holds an unrelated and unmanaged
pointer ptr. Even if this shared_ptr is the last of the group to go out of scope, it will call the destructor for the object originally managed by r. However, calling get() on this will always return a copy of ptr. It is the responsibility of the programmer to make sure that this ptr remains valid as long as this shared_ptr exists, such as in the typical use cases where ptr is a member of the object managed by r or is an alias (e.g., downcast) of r.get()
- Constructs a shared_ptr which shares ownership information with r, but holds an unrelated and unmanaged