Was ist boost der shared_ptr (shared_ptr const & r, T * p) verwendet?
-
05-07-2019 - |
Frage
boost::shared_ptr
hat eine ungewöhnliche Konstruktor
template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);
, und ich bin ein wenig verwirrt darüber, was dies für sinnvoll wäre. Grundsätzlich teilt es Eigentum mit r
, aber .get()
wird p
zurück. nicht r.get()
!
Dies bedeutet, dass Sie etwas tun können:
int main() {
boost::shared_ptr<int> x(new int);
boost::shared_ptr<int> y(x, new int);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
Und Sie werden diese:
0x8c66008
0x8c66030
2
2
Beachten Sie, dass die Zeiger sind getrennt, aber sie behaupten, sowohl eine use_count
von 2 haben (da sie das Eigentum an dem gleichen Objekt teilen).
Also, die int
von x
Besitz wird solange x
existieren oder y
um ist. Und wenn ich die Dokumentation richtig verstehen, wird die zweite int
nie zerstört. Ich habe dies mit dem folgende Testprogramm bestätigt:
struct T {
T() { std::cout << "T()" << std::endl; }
~T() { std::cout << "~T()" << std::endl; }
};
int main() {
boost::shared_ptr<T> x(new T);
boost::shared_ptr<T> y(x, new T);
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
std::cout << x.use_count() << std::endl;
std::cout << y.use_count() << std::endl;
}
Diese gibt (wie erwartet):
T()
T()
0x96c2008
0x96c2030
2
2
~T()
Also ... was ist der Nutzen dieses ungewöhnlichen Konstrukts, das Eigentum an einem Zeiger teilt, aber wirkt wie ein zweiten Zeiger (was sie nicht besitzen), wenn verwendet.
Lösung
Es ist nützlich, wenn Sie einen Teilnehmer, und eine Instanz der Klasse teilen wollen, ist bereits ein shared_ptr, wie folgt aus:
struct A
{
int *B; // managed inside A
};
shared_ptr<A> a( new A );
shared_ptr<int> b( a, a->B );
sie die Verwendung Zahl und Sachen teilen. Es ist die Optimierung für die Speichernutzung.
Andere Tipps
Leiz zu erweitern und Piotrs Antworten, diese Beschreibung von shared_ptr<>
' Aliasing‘ist aus einem WG21 Papier, "Die Verbesserung der shared_ptr
für C ++ 0x, Revision 2" :
III. Aliasing Unterstützung
Fortgeschrittene Benutzer erfordern oft die Fähigkeit, eine
shared_ptr
zu erstellen Beispielp
, dass das Eigentum teilt mit Weitere (Master)shared_ptr
q
aber auf ein Objekt, das nicht eine Base von*q
.*p
kann ein Mitglied oder eine Element*q
, zum Beispiel. Diese Abschnitt schlägt eine zusätzliche Konstruktor, der dafür verwendet werden kann, Zweck.Ein interessanter Nebeneffekt dieser Steigerung der Ausdruckskraft ist, dass jetzt die
*_pointer_cast
Funktionen können werden in Benutzercode implementiert. Dasmake_shared
Fabrik Funktion vorgestellt später in diesem Dokument kann auch sein, implementiert nur die Öffentlichkeit mit Schnittstelle vonshared_ptr
über das Aliasing-Konstruktor.Auswirkungen:
Diese Funktion erweitert die Schnittstelle von
shared_ptr
in einer rückwärtskompatibel Art und Weise, die ihren Ausdruck erhöht Leistung und ist daher stark empfohlen, die C ++ 0x hinzugefügt werden Standard. Es führt keine Quellen- und binäre Kompatibilitätsprobleme.Textvorschlag:
In den
shared_ptr
[Util.smartptr.shared] die folgende Konstruktor:template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
Fügen Sie Folgendes [Util.smartptr.shared.const]:
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
Effekte: Konstruiert eine
.shared_ptr
Instanz, diep
und Aktien Eigentum mitr
speichertNachbedingungen:.
get() == p && use_count() == r.use_count()
Wirft:. nichts
[Anmerkung: , um die Möglichkeit eines baumelnden Zeiger zu vermeiden, den Benutzer dieser Konstruktor muss, dass
p
gewährleisten bleibt gültig mindestens bis die Eigentümergrupper
zerstört. -. Endnote][Hinweis: Dieser Konstruktor ermöglicht die Erstellung eines leer
shared_ptr
Beispiel mit einem nicht-NULL-Zeiger gespeichert. -. Endnote]
Sie können dies auch dynamische gegossene Zeiger zu halten verwenden, das heißt:.
class A {};
class B: public A {};
shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
Sie können einen Zeiger auf einen Fahrer oder ein niedrigeren Datenstruktur Niveau api, die von seiner unteren Ebene api oder anderen Mitteln zusätzliche Daten zuordnen kann. In diesem Fall könnte es interessant sein, die use_count zu erhöhen, aber die zusätzlichen Daten zurück, wenn der erste Zeiger die anderen Datenzeiger besitzt.
Ich habe Shared_ptr des Aliasing-Konstruktor in Gebrauch in meiner kleinen Bibliothek setzen:
http://code.google.com/p/infectorpp/ (nur meine einfache IoC-Container)
Der Punkt ist, dass, da ich ein shared_ptr bekannten Art benötigt, um von einer polymorphen Klasse zurückgegeben werden (also nicht die Art nicht kennt). Ich war nicht in der Lage, implizit die shared_ptr auf den Typ zu umwandeln ich brauchte.
In der Datei „ InfectorHelpers.hpp “(Zeile 72-99) können Sie, dass in Aktion für den Typen siehe IAnyShared.
Aliasing-Konstruktor erstellt shared_ptr, die nicht die Zeiger löscht sie tatsächlich zeigt auf, sondern sie noch den Referenzzähler erhöhen auf das ursprüngliche Objekt und das kann enorm nützlich sein.
Grundsätzlich können Sie einen Zeiger auf etwas schaffen mit Aliasing-Konstruktor und Bedrohung als Referenzzähler.
//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress
virtual std::shared_ptr<int> getReferenceCounter(){
return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}
virtual void* getPtr(); //return raw pointer to T
Jetzt haben wir beide „einen Referenzzähler“ und einen Zeiger auf eine istance von T, genug Daten etwas mit dem Aliasing-Konstruktor erstellen
std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter
static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!
Ich behaupte nicht, diese Verwendung für das Aliasing-Konstruktor erfunden zu haben, aber ich habe nie jemand anderes tut das gleiche gesehen. Wenn Sie erraten, wenn die schmutzige Code funktioniert die Antwort ja.
"shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
"
Ich denke, es ist nicht der empfohlene Weg Smart-Pointer verwendet wird.
Es wird empfohlen, diese Art Umwandlung tun sollte:
shared_ptr<B> b(a);
Da in Boost-Dokument wird erwähnt, dass:
shared_ptr<T>
kann implizit sein umgerechnet aufshared_ptr<U>
T, wenn * implizit in U * umgewandelt werden. Im Insbesondereshared_ptr<T>
ist implizit konvertierbarshared_ptr<T> const
,shared_ptr<U>
wobei U ein ist, zugänglich Basis von T, undshared_ptr<void>
.
Neben dem haben wir auch dynamic_pointer_cast die auf Smart Pointer-Objekt und beide diese beiden Methoden wäre viel sicherer als die von Hand Gießen Rohzeiger Art und Weise direkt Umwandlung tun könnte.