Gibt intelligente Zeiger nach Wert zurück.
Wie Sie bereits gesagt haben, erhöhen Sie den Referenzzähler nicht richtig, wenn Sie ihn als Referenz zurückgeben, was das Risiko erhöht, dass etwas zum falschen Zeitpunkt gelöscht wird. Das allein sollte Grund genug sein, nicht per Referenz zurückzukehren. Schnittstellen sollten robust sein.
Das Kostenproblem ist heutzutage dank der Rückgabewertoptimierung (RVO) umstritten, sodass bei modernen Compilern keine Inkrement-Inkrement-Dekrement-Sequenz oder ähnliches auftritt. Der beste Weg, a zurückzugeben, shared_ptr
besteht darin, einfach nach Wert zurückzugeben:
shared_ptr<T> Foo()
{
return shared_ptr<T>(/* acquire something */);
};
Dies ist eine absolut offensichtliche RVO-Möglichkeit für moderne C ++ - Compiler. Ich weiß, dass Visual C ++ - Compiler RVO auch dann implementieren, wenn alle Optimierungen deaktiviert sind. Und mit der Verschiebungssemantik von C ++ 11 ist dieses Problem noch weniger relevant. (Der einzige Weg, um sicher zu sein, ist das Profilieren und Experimentieren.)
Wenn Sie immer noch nicht überzeugt sind, hat Dave Abrahams einen Artikel , der ein Argument für die Rückkehr nach Wert liefert. Ich reproduziere hier einen Ausschnitt; Ich empfehle Ihnen dringend, den gesamten Artikel zu lesen:
Seien Sie ehrlich: Wie fühlen Sie sich mit dem folgenden Code?
std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();
Ehrlich gesagt, obwohl ich es besser wissen sollte, macht es mich nervös. Grundsätzlich müssen get_names()
wir bei der Rücksendung a vector
von string
s kopieren . Dann müssen wir es bei der Initialisierung erneut kopieren
names
und die erste Kopie zerstören. Wenn string
der Vektor N s enthält, kann jede Kopie bis zu N + 1 Speicherzuweisungen und eine ganze Reihe von cache-unfreundlichen Datenzugriffen erfordern,> wenn der String-Inhalt kopiert wird.
Anstatt mich dieser Art von Angst zu stellen, habe ich oft auf Pass-by-Reference zurückgegriffen, um unnötige Kopien zu vermeiden:
get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );
Leider ist dieser Ansatz alles andere als ideal.
- Der Code wuchs um 150%
- Wir mussten
const
-ness fallen lassen, weil wir Namen mutieren.
- Wie funktionale Programmierer uns gerne daran erinnern, macht die Mutation die Argumentation von Code komplexer, indem sie die referenzielle Transparenz und das Argumentationsgleich untergräbt.
- Wir haben keine strikte Wertesemantik mehr für Namen.
Aber ist es wirklich notwendig, unseren Code auf diese Weise durcheinander zu bringen, um die Effizienz zu steigern? Glücklicherweise lautet die Antwort nein (und insbesondere nicht, wenn Sie C ++ 0x verwenden).