Kann ich warf shared_ptr<T> & zu shared_ptr<T const> & ohne änderung use_count?
Ich habe ein Programm, das mit boost::shared_ptr
s und insbesondere, verlässt sich auf die Genauigkeit der use_count
um Optimierungen durchzuführen.
Beispielsweise vorstellen, eine addition mit zwei argument-Zeiger genannt lhs und rhs. Sagen, Sie haben beide den Typ shared_ptr<Node>
. Wenn es Zeit, um die Ergänzung, ich werde prüfen, die use_count
, und wenn ich finde, dass eines der Argumente hat einen reference count von genau einer, dann werde ich es wiederverwenden, um den Vorgang auszuführen, statt. Wenn weder argument kann wiederverwendet werden, muss ich reservieren einer neuen Daten-Puffer und führen Sie die operation out-of-Platz. Ich bin den Umgang mit den enormen Daten-Strukturen, so dass die in-place-Optimierung ist sehr vorteilhaft.
Da kann ich nie kopieren Sie die shared_ptr
s ohne Grund, D. H., jede Funktion nimmt die shared_ptr
s durch Referenz oder const-Referenz zu vermeiden, verzerren use_count
.
Meine Frage ist: ich habe manchmal das shared_ptr<T> &
ich will zu werfen, um shared_ptr<T const> &
, aber wie kann ich es tun, ohne zu verzerren die Anzahl der? static_pointer_cast
gibt ein neues Objekt eher als eine Referenz. Ich würde geneigt sein, zu denken, dass es funktionieren würde, nur werfen die ganze shared_ptr
wie in:
void f(shared_ptr<T> & x)
{
shared_ptr<T const> & x_ = *reinterpret_cast<shared_ptr<T const> *>(&x);
}
Bezweifle ich stark, dies entspricht dem standard, aber, wie ich schon sagte, es wird wahrscheinlich funktionieren. Gibt es eine Möglichkeit, das zu tun, garantiert sicher und richtig?
Aktualisierung zu Konzentrieren, die Frage
Kritisieren das design nicht helfen, die Antwort in diesem post. Es gibt zwei interessante Fragen zu berücksichtigen:
-
Gibt es keine Garantie (der Verfasser der
boost::shared_ptr
oder von der Norm, im Fall derstd::tr1::shared_ptr
), dieshared_ptr<T>
undshared_ptr<T const>
haben die gleichen layouts und Verhalten? -
Wenn (1) wahr ist, dann ist die oben eine Legale Verwendung von reinterpret_cast? Ich denke, Sie würden sein hart gedrückt, um finden ein compiler erzeugt fehlerhaften code für das obige Beispiel, aber das bedeutet nicht, dass es legal ist. Was auch immer Ihre Antwort, können Sie Unterstützung finden, für die es in der C++ standard?
- Mit dem Verweis für die Zählung in einer Weise sieht aus wie eine sehr eigenartige design der route. Warum nicht setzen einige Kontrolle darüber, ob ein Vorgang geschieht, oder durch kopieren auf den Benutzer? Oder separate gemeinsame und eindeutige Hinweise?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht. Das Konzept ist falsch. Überlegen Sie, was passiert mit einer nackten Zeiger
T*
undconst T*
. Wenn Sie werfen Sie IhreT*
in eineconst T*
haben Sie jetzt zwei Zeiger. Sie müssen nicht zwei Verweise auf die gleichen Zeiger; Sie haben zwei Zeiger.Warum sollte das anders sein, für smart-Pointer? Sie haben zwei Zeiger: der eine, um ein
T
, und zu einemconst T
. Sie beide teilen sich das Eigentum an der gleichen Objekt, so dass Sie mit zwei von Ihnen. Ihreuse_count
daher sollten 2, nicht 1.Dein problem ist dein Versuch, um eine überlastung der Bedeutung von
use_count
, co-opting seine Funktionalität für andere Zwecke. Kurz gesagt: du machst es falsch.Ihre Beschreibung, was Sie tun, mit
shared_ptr
s, wer ' suse_count
ist, ist... erschreckend. Sie sind im Grunde sagen, dass bestimmte Funktionen kooptieren eines Ihrer Argumente, die der Aufrufer ist klar Verwendung (da der Anrufer offenbar ist es immer noch mit). Und der Anrufer nicht weiß, welche man in Anspruch genommen wurde (wenn überhaupt), so der Anrufer hat keine Ahnung, was der Staat von den Argumenten, die nach der Funktion. Ändern Sie die Argumente für Operationen wie das ist in der Regel nicht eine gute Idee.Plus das, was du machst kann nur funktionieren, wenn Sie pass
shared_ptr<T>
durch die Referenz, die selbst keine gute Idee ist (wie normale Zeiger, smart-Pointer, sollten fast immer berücksichtigt werden by-value).Kurz gesagt, Sie sind eine sehr Häufig verwendete Objekt mit wohldefinierten Redewendungen und Semantik, dann die Forderung, dass es in einer Weise verwendet werden, dass Sie fast nie verwendet, mit spezieller Semantik, die Arbeit gegen die Art und Weise eigentlich jeder nutzt Sie. Ist das nicht eine gute Sache.
Haben Sie effektiv erstellt das Konzept der co-optable Zeiger, der auf einen shared pointer kann in 3 Zustände: leer, von der person, die Sie dir gegeben hat und somit kann man es stehlen, und in der Verwendung von mehr als einer person, so dass Sie können es nicht haben. Es ist nicht die Semantik, dass
shared_ptr
vorhanden ist, zu unterstützen. So sollten Sie schreiben Sie Ihre eigenen smart-pointer, bietet diese Semantik auf eine viel natürlichere Weise.Etwas erkennt, daß der Unterschied zwischen, wie viele Instanzen von einem Zeiger, die Sie haben, um, und, wie viele tatsächliche Nutzer Sie haben. So kann es passieren, um durch den Wert richtig funktioniert, Sie aber die Möglichkeit haben, zu sagen, dass Sie derzeit verwenden und nicht möchten, dass eine dieser anderen Funktionen zu machen. Es könnte
shared_ptr
intern, aber es sollte seine eigene Semantik.shared_ptr
auf einen Wert) ist temporär und somit, ob es sicher ist, zu überschreiben.use_count
, in der Erwägung, dass es funktionieren sollte, wenn die Einnahme von Zeiger durch Wert. Auch unter shared_ptrs Verweis ist üblich und empfohlen, für bestimmte Umstände. Siehe mein Antwort.shared_ptr<T>&
s überall, sind keine gute Idee. Entweder eine Funktion zustehenden Forderungen Eigentum von die Erinnerung (und damit sollte eineshared_ptr
- by-value), oder es nicht, und somit sollte eine nackt-Zeiger.shared_ptr
in das Objekt (oder gerade frisch zugeordnet eine vorübergehende). Er behauptet nicht-C++11 Gebrauch, und er ist mitboost::shared_ptr
. Es ist also sehr wahrscheinlich, dass er die übergabe von Referenzen um, in der Erwartung, dassuse_count==1
zu verstehen, dass nur die Anrufer zu verwenden, und es ist gut zu kooptieren es. Ich kann nicht sicher sein, aber das ist meine interpretation von seiner Beschreibung..shared_ptr
per Wert an eine Funktion und habe es immer noch nur im Besitz von einem Benutzer der ist, für es zu eine vorübergehende. Also ich nehme an, er hat es mit Hilfe von Referenz.static_pointer_cast
ist das richtige Werkzeug für den job — Sie haben bereits festgestellt, dass.Das problem dabei ist nicht, dass es gibt ein neues Objekt, sondern vielmehr, dass es verlässt das alte Objekt unverändert. Sie wollen, um loszuwerden, die non-const-Zeiger und bewegen sich mit der const-Zeiger. Was Sie wirklich wollen, ist
static_pointer_cast< T const >( std::move( old_ptr ) )
. Aber gibt es nicht eine überlastung für rvalue-Referenzen.Die Abhilfe ist einfach: manuell erlischt die alten Zeiger nur als
std::move
würde.Es könnte etwas langsamer sein, als
reinterpret_cast
, aber es ist viel mehr wahrscheinlich, um zu arbeiten. Unterschätzen Sie nicht, wie Komplex die Bibliothek-implementation ist, und wie er kann fehlschlagen, wenn Sie missbraucht werden.Nebenbei: verwenden Sie
pointer.unique()
stattuse_count() == 1
. Einige Implementierungen verwenden eine verknüpfte Liste mit no-Cache verwenden Sie count, so dassuse_count()
O(N) in der Erwägung, dass dieunique
test bleibt O(1). Der Standard empfiehltunique
für copy-on-write-Optimierung.EDIT: Jetzt sehe ich Sie erwähnen
Dies ist etwas Falsch. Sie haben Hinzugefügt eine weitere Schicht von Besitz-Semantik auf, was
shared_ptr
bereits tut. Sie sollte durch Wert übergeben werden, mitstd::move
eingesetzt werden, wo der Anrufer nicht mehr von Eigentum. Wenn der profiler sagt, Sie verbringen Zeit mit der Anpassung von Referenz zählt, dann könnten Sie fügen Sie einige Referenzen auf Zeiger in den inneren Schleifen. Aber als Allgemeine Regel gilt, wenn Sie nicht festlegen können, ein Zeiger aufnullptr
weil Sie nicht mehr mit, aber könnte jemand anderes sein, dann haben Sie wirklich den überblick verloren, Eigentum.Wenn Sie die Umwandlung eine
shared_ptr
auf eine andere Art, ohne dabei die Referenz-Zählung bedeutet dies, dass Sie haben nun zwei Zeiger auf die gleichen Daten. Daher, es sei denn, Sie löschen die alten Zeiger, können Sie es nicht mitshared_ptr
s ohne "Verzerrung der reference count".Ich würde vorschlagen, dass Sie verwenden Sie roh-Zeiger hier statt, anstatt von Ihr Weg, um nicht die Verwendung der Funktionen von
shared_ptr
s. Wenn Sie brauchen, um manchmal neue Referenzen, verwendenenable_shared_from_this
um daraus einen neuenshared_ptr
zu einer vorhandenen raw-pointer.shared_ptr
kann nicht machen, eine solche Garantie. Du bist casting zwischen zwei verschiedenen raw-Typen, und der compiler übernimmt keine Gewähr dafür, dassshared_ptr<const int>
hat die gleiche Darstellung wieshared_ptr<int>
, unabhängig davon, was dieshared_ptr
Autoren tun.Dies ist nicht unbedingt gültig, es sei denn, Sie anwenden, einige andere Regeln über das gesamte Programm, die es so machen. Bedenken Sie:
Statt, wenn man die intelligente Zeiger durch Wert:
Und die use_count()==1, dann wissen Sie, dass Ihre Kopie ist der einzige, und es sollte sicher sein, um es der wiederverwertung zuzuführen.
Allerdings gibt es ein problem in der Verwendung dieser als eine Optimierung, da beim kopieren eines shared_ptr erfordert die Synchronisation. Es könnte gut sein, dass Sie all diese Synchronisierung alle über dem Platz kostet weit mehr, als Sie sparen durch Wiederverwendung vorhandener shared_ptrs. Alle diese Synchronisierung ist der Grund, es wird empfohlen, den code, der nicht in Besitz nehmen einen shared_ptr, der sollte shared_ptr per reference anstatt per value.
shared_ptr
s benötigt nur atomar inkrementiert und dekrementiert. Und, wie Sie, wenn Sie Sie bewegen, dann ist es nicht einmal erforderlich, dass. So nehmen Sie von Wert ist immer noch in Ordnung. Und wenn Sie nicht Vorhaben, zu behaupten, die Eigentümer von Ihnen, dann Sie sollte nicht untershared_ptr
s überhaupt.use_count()
für diese.const&
wie Sie sehen, passen. Plus, es richtet mit der "immerunique_ptr
Wert" beraten. Es ist einfacher zu merken zwei Regeln als eine.shared_ptr
, dann sollte der Benutzer davon aus, dass es Besitzrechte. Wenn jeder nimmtshared_ptr
s zu diesen Objekten, dann ist es schwieriger, die Spur zu dem Besitz der graph.shared_ptr
by-ref sollte üblich sein. Ich persönlich Stimme ich mit Nicol. Wenn der code nicht mehrshared_ptr
Funktionalität, es sollte nur einenNode&
oderNode const&
, und der Anrufer einfach geht*ptr
. Warum beschränken Sie Ihre Optionen durch das erzwingen der Verwendung einesshared_ptr
?shared_ptr
überall; es bezeichnet die übertragung des Eigentums, nicht "hier, verwenden Sie diese für ein bisschen."shared_ptr
ist manchmal gesehen, wie eine Lizenz zu vergessen über Besitz-und Speicher-management. Und dieser Weg führt zu Speicherlecks durch zirkulären Verweis, oder einfach, um Sachen, um länger, als es sein muss.shared_ptr
wird keine Lizenz zur nicht verstehen, ein Programm, das Eigentumsrecht Grafik, aber die Art und Weise zu verstehen, das Eigentum nicht zu gehen, obwohl Sie alle den code und sehen, wer ' s Tod, was, wo. shared_ptr ist ein RAII geben und zu sehen, es ging sollte sagen, der Leser genau das, was man eine RAII-Typ übergeben würde, nämlich, dass der lokale code wird verlassen Sie das management dieser Ressourcen bis zu dem RAII-Objekt. Immer das größere Bild, wer was besitzt und sicherzustellen, dass die gesamten Besitz-graph ist ein DAG ist Links zu anderen Geräten.