Ich möchte einen gemeinsamen Zeiger an eine Funktion übergeben. Kannst du mir damit helfen?
Klar, das kann ich dir helfen. Ich gehe davon aus, dass Sie ein gewisses Verständnis der Besitzersemantik in C ++ haben. Ist das wahr?
Ja, ich bin ziemlich zufrieden mit dem Thema.
Gut.
Ok, ich kann mir nur zwei Gründe vorstellen, um ein shared_ptr
Argument anzunehmen:
- Die Funktion möchte das Eigentum an dem Objekt teilen.
- Die Funktion führt eine Operation aus, die speziell für
shared_ptr
s funktioniert .
Für welches interessieren Sie sich?
Ich suche nach einer allgemeinen Antwort, also interessiere ich mich eigentlich für beides. Ich bin allerdings gespannt, was Sie in Fall 2 meinen.
Beispiele für solche Funktionen sind std::static_pointer_cast
benutzerdefinierte Komparatoren oder Prädikate. Wenn Sie beispielsweise alle eindeutigen shared_ptr aus einem Vektor suchen müssen, benötigen Sie ein solches Prädikat.
Ah, wenn die Funktion tatsächlich den Smart Pointer selbst manipulieren muss.
Genau.
In diesem Fall sollten wir meiner Meinung nach als Referenz dienen.
Ja. Und wenn sich der Zeiger dadurch nicht ändert, möchten Sie die const-Referenz übergeben. Sie müssen nicht kopieren, da Sie das Eigentum nicht teilen müssen. Das ist das andere Szenario.
OK habe es. Lassen Sie uns über das andere Szenario sprechen.
Der, an dem Sie das Eigentum teilen? OK. Wie teilen Sie das Eigentum mit shared_ptr
?
Durch Kopieren.
Dann muss die Funktion eine Kopie von a shared_ptr
erstellen, richtig?
Offensichtlich. Also übergebe ich es durch einen Verweis auf const und kopiere es in eine lokale Variable?
Nein, das ist eine Pessimisierung. Wenn es als Referenz übergeben wird, hat die Funktion keine andere Wahl, als die Kopie manuell zu erstellen. Wenn es als Wert übergeben wird, wählt der Compiler die beste Wahl zwischen einer Kopie und einer Verschiebung und führt sie automatisch aus. Übergeben Sie also den Wert.
Guter Punkt. Ich muss mich öfter an den Artikel " Willst du Geschwindigkeit? Pass by Value " erinnern .
Warten Sie, was ist, wenn die Funktion das beispielsweise shared_ptr
in einer Mitgliedsvariablen speichert ? Wird das nicht eine redundante Kopie machen?
Die Funktion kann das shared_ptr
Argument einfach in seinen Speicher verschieben. Das Verschieben von a shared_ptr
ist billig, da es keine Referenzanzahl ändert.
Ah, gute Idee.
Aber ich denke an ein drittes Szenario: Was ist, wenn Sie das nicht manipulieren shared_ptr
oder das Eigentum teilen wollen?
In diesem Fall shared_ptr
ist für die Funktion völlig irrelevant. Wenn Sie den Pointee manipulieren möchten, nehmen Sie einen Pointee und lassen Sie die Anrufer auswählen, welche Besitzersemantik sie möchten.
Und sollte ich den Pointee als Referenz oder als Wert nehmen?
Es gelten die üblichen Regeln. Intelligente Zeiger ändern nichts.
Übergeben Sie den Wert, wenn ich kopieren möchte, und übergeben Sie ihn als Referenz, wenn ich eine Kopie vermeiden möchte.
Richtig.
Hmm. Ich denke, Sie haben noch ein anderes Szenario vergessen. Was ist, wenn ich das Eigentum teilen möchte, aber nur abhängig von einer bestimmten Bedingung?
Ah, ein interessanter Randfall. Ich erwarte nicht, dass das oft passiert. In diesem Fall können Sie entweder den Wert übergeben und die Kopie ignorieren, wenn Sie sie nicht benötigen, oder als Referenz übergeben und die Kopie erstellen, wenn Sie sie benötigen.
Ich riskiere eine redundante Kopie in der ersten Option und verliere einen möglichen Zug in der zweiten. Kann ich den Kuchen nicht essen und ihn auch haben?
Wenn Sie sich in einer Situation befinden, in der dies wirklich wichtig ist, können Sie zwei Überladungen bereitstellen, eine mit einer Konstantenwertreferenz und eine mit einer Wertreferenz. Eine Kopie, die andere bewegt sich. Eine perfekte Weiterleitungsfunktionsvorlage ist eine weitere Option.
Ich denke, das deckt alle möglichen Szenarien ab. Vielen Dank.
const std::shared_ptr<myClass>& arg1