Das ist ein wenig subjektiv, denke ich; Ich bin mir nicht sicher, ob die Meinung einstimmig sein wird (ich habe viele Codefragmente gesehen, in denen Referenzen zurückgegeben werden).
Laut einem Kommentar zu dieser Frage, den ich gerade bezüglich der Initialisierung von Referenzen gestellt habe , kann die Rückgabe einer Referenz böse sein, da es [soweit ich weiß] einfacher ist, das Löschen zu übersehen, was zu Speicherverlusten führen kann.
Das macht mir Sorgen, da ich Beispielen gefolgt bin (es sei denn, ich stelle mir Dinge vor) und dies an einigen Stellen getan habe ... Habe ich das falsch verstanden? Ist es böse? Wenn ja, wie böse?
Ich habe das Gefühl, dass meine Anwendungen aufgrund meiner gemischten Menge an Zeigern und Referenzen, kombiniert mit der Tatsache, dass ich neu in C ++ bin, und der völligen Verwirrung darüber, was wann verwendet werden soll, Speicherleck sein müssen ...
Ich verstehe auch, dass die Verwendung von intelligenten / gemeinsam genutzten Zeigern allgemein als der beste Weg zur Vermeidung von Speicherlecks akzeptiert wird.
Antworten:
Im Allgemeinen ist die Rückgabe einer Referenz völlig normal und geschieht ständig.
Wenn du meinst:
Das ist alles Böse. Der zugewiesene Stapel verschwindet
i
und Sie beziehen sich auf nichts. Das ist auch böse:Denn jetzt muss der Kunde irgendwann das Seltsame tun:
Beachten Sie, dass rWert-Referenzen immer noch nur Referenzen sind, sodass alle bösen Anwendungen gleich bleiben.
Wenn Sie etwas zuweisen möchten, das über den Funktionsumfang hinausgeht, verwenden Sie einen intelligenten Zeiger (oder allgemein einen Container):
Und jetzt speichert der Client einen intelligenten Zeiger:
Referenzen sind auch für den Zugriff auf Dinge in Ordnung, bei denen Sie wissen, dass die Lebensdauer auf einer höheren Ebene offen gehalten wird, z.
Hier wissen wir, dass es in Ordnung ist, einen Verweis auf zurückzugeben,
i_
da alles, was uns aufruft, die Lebensdauer der Klasseninstanz verwalteti_
mindestens so lange lebt.Und natürlich ist nichts falsch daran, nur:
Wenn die Lebensdauer dem Anrufer überlassen bleiben soll und Sie nur den Wert berechnen.
Zusammenfassung: Es ist in Ordnung, eine Referenz zurückzugeben, wenn die Lebensdauer des Objekts nach dem Aufruf nicht endet.
quelle
return new int
Sie aus Gründen der Nachwelt und für neuere Programmierer, die darauf stoßen, nicht .Nein, nein, tausendmal nein.
Was böse ist, ist ein Verweis auf ein dynamisch zugewiesenes Objekt und der Verlust des ursprünglichen Zeigers. Wenn Sie
new
ein Objekt haben, übernehmen Sie die Verpflichtung, eine Garantie zu habendelete
.Aber schauen Sie sich zB an
operator<<
: das muss eine Referenz zurückgeben, oderwird nicht funktionieren.
quelle
Sie sollten einen Verweis auf ein vorhandenes Objekt zurückgeben, das nicht sofort verschwindet und bei dem Sie keine Eigentumsübertragung beabsichtigen.
Geben Sie niemals einen Verweis auf eine lokale Variable oder eine solche zurück, da dieser nicht zum Verweisen da ist.
Sie können einen Verweis auf etwas zurückgeben, das von der Funktion unabhängig ist. Sie erwarten nicht, dass die aufrufende Funktion die Verantwortung für das Löschen übernimmt. Dies ist der Fall für die typischen
operator[]
Funktion .Wenn Sie etwas erstellen, sollten Sie entweder einen Wert oder einen Zeiger (normal oder intelligent) zurückgeben. Sie können einen Wert frei zurückgeben, da er in der aufrufenden Funktion in eine Variable oder einen Ausdruck eingeht. Geben Sie niemals einen Zeiger auf eine lokale Variable zurück, da diese nicht mehr angezeigt wird.
quelle
Ich finde die Antworten nicht zufriedenstellend, also addiere ich meine zwei Cent.
Lassen Sie uns die folgenden Fälle analysieren:
Fehlerhafte Verwendung
Dies ist offensichtlich ein Fehler
Verwendung mit statischen Variablen
Dies ist richtig, da statische Variablen während der gesamten Lebensdauer eines Programms vorhanden sind.
Dies ist auch bei der Implementierung von Singleton-Mustern häufig der Fall
Verwendungszweck:
Betreiber
Standardbibliothekscontainer hängen stark von der Verwendung von Operatoren ab, die beispielsweise Referenzen zurückgeben
kann im Folgenden verwendet werden
Schneller Zugriff auf interne Daten
Es gibt Zeiten, in denen & für den schnellen Zugriff auf interne Daten verwendet werden kann
mit Verwendung:
Dies kann jedoch zu einer solchen Gefahr führen:
quelle
true
If((a*b) == (c*d))
Container::data()
Die Implementierung sollte lautenreturn m_data;
Es ist nicht böse. Wie viele Dinge in C ++ ist es gut, wenn es richtig verwendet wird, aber es gibt viele Fallstricke, die Sie bei der Verwendung beachten sollten (z. B. die Rückgabe eines Verweises auf eine lokale Variable).
Es gibt gute Dinge, die damit erreicht werden können (wie map [name] = "Hallo Welt")
quelle
map[name] = "hello world"
?HashMap<String,Integer>
in Java gespeicherten Werte zu erhöhen? : PNicht wahr. Die Rückgabe einer Referenz impliziert keine Besitzersemantik. Das heißt, nur weil Sie dies tun:
... bedeutet nicht, dass Sie jetzt den Speicher besitzen, auf den sich v bezieht;
Dies ist jedoch ein schrecklicher Code:
Wenn Sie so etwas tun, weil "Sie für diese Instanz keinen Zeiger benötigen", dann: 1) dereferenzieren Sie den Zeiger einfach, wenn Sie eine Referenz benötigen, und 2) benötigen Sie schließlich den Zeiger, weil Sie mit a übereinstimmen müssen Neu mit einem Löschvorgang, und Sie benötigen einen Zeiger, um den Löschvorgang aufzurufen.
quelle
Es gibt zwei Fälle:
const reference - gute Idee, manchmal, insbesondere für schwere Objekte oder Proxy-Klassen, Compiler-Optimierung
Non-Const-Referenz - Bad Idee bricht manchmal Kapselungen
Beide haben dasselbe Problem - können möglicherweise auf ein zerstörtes Objekt hinweisen ...
Ich würde empfehlen, intelligente Zeiger für viele Situationen zu verwenden, in denen Sie eine Referenz / einen Zeiger zurückgeben müssen.
Beachten Sie auch Folgendes:
Es gibt eine formale Regel - der C ++ - Standard (Abschnitt 13.3.3.1.4, wenn Sie interessiert sind) besagt, dass eine temporäre Referenz nur an eine const-Referenz gebunden werden kann - wenn Sie versuchen, eine nicht-const-Referenz zu verwenden, muss der Compiler dies als kennzeichnen ein Fehler.
quelle
Es ist nicht nur nicht böse, es ist manchmal wesentlich. Zum Beispiel wäre es unmöglich, den Operator [] von std :: vector zu implementieren, ohne einen Referenzrückgabewert zu verwenden.
quelle
operator[]
für einen Container ohne Verwendung einer Referenz implementieren ... undstd::vector<bool>
das auch. (Und schafft dabei ein echtes Durcheinander)::std::vector<bool>
Sie bereits erwähnt haben).std::vector<T>
im VorlagencodeT
möglicherweise unterbrochen istbool
, da sichstd::vector<bool>
das Verhalten von anderen Instanziierungen stark unterscheidet. Es ist nützlich, sollte aber einen eigenen Namen haben und keine Spezialisierung vonstd::vector
.Ergänzung zur akzeptierten Antwort:
Ich würde argumentieren, dass dieses Beispiel nicht in Ordnung ist und wenn möglich vermieden werden sollte. Warum? Es ist sehr leicht, eine baumelnde Referenz zu erhalten .
Um den Punkt anhand eines Beispiels zu veranschaulichen:
Betreten der Gefahrenzone:
quelle
Die Rückgabereferenz wird normalerweise beim Überladen von Operatoren in C ++ für große Objekte verwendet, da für das Zurückgeben eines Werts eine Kopieroperation erforderlich ist (beim Überladen von Peratoren wird normalerweise kein Zeiger als Rückgabewert verwendet).
Die Rückgabereferenz kann jedoch zu Speicherproblemen führen. Da eine Referenz auf das Ergebnis als Referenz auf den Rückgabewert aus der Funktion übergeben wird, kann der Rückgabewert keine automatische Variable sein.
Wenn Sie die Rückgabe der Referenz verwenden möchten, können Sie einen Puffer mit statischen Objekten verwenden. zum Beispiel
Auf diese Weise können Sie die Rückgabereferenz sicher verwenden.
Sie können jedoch immer einen Zeiger anstelle einer Referenz verwenden, um den Wert in functiong zurückzugeben.
quelle
Ich denke, die Verwendung von Referenz als Rückgabewert der Funktion ist viel einfacher als die Verwendung von Zeigern als Rückgabewert der Funktion. Zweitens wäre es immer sicher, eine statische Variable zu verwenden, auf die sich der Rückgabewert bezieht.
quelle
Am besten erstellen Sie ein Objekt und übergeben es als Referenz- / Zeigerparameter an eine Funktion, die diese Variable zuweist.
Das Zuweisen eines Objekts in der Funktion und das Zurückgeben als Referenz oder Zeiger (Zeiger ist jedoch sicherer) ist eine schlechte Idee, da am Ende des Funktionsblocks Speicher freigegeben wird.
quelle
Die Funktion getPtr kann nach dem Löschen oder sogar auf ein Nullobjekt auf den dynamischen Speicher zugreifen. Dies kann zu Ausnahmen beim fehlerhaften Zugriff führen. Stattdessen sollten Getter und Setter implementiert und die Größe überprüft werden, bevor Sie zurückkehren.
quelle
Die Funktion als Wert (auch bekannt als Rückgabe von nicht konstanten Referenzen) sollte aus C ++ entfernt werden. Es ist schrecklich unintuitiv. Scott Meyers wollte eine Minute () mit diesem Verhalten.
Das ist keine wirkliche Verbesserung
Letzteres macht noch mehr Sinn.
Mir ist klar, dass die Funktion als Wert für Streams im C ++ - Stil wichtig ist, aber es ist erwähnenswert, dass Streams im C ++ - Stil schrecklich sind. Ich bin nicht der Einzige, der das denkt ... Ich erinnere mich, dass Alexandrescu einen großen Artikel darüber veröffentlicht hat, wie man es besser macht, und ich glaube, Boost hat auch versucht, eine bessere typsichere E / A-Methode zu entwickeln.
quelle
vector::operator[]
zum Beispiel. Möchten Sie lieber schreibenv.setAt(i, x)
oderv[i] = x
? Letzteres ist weit überlegen.v.setAt(i, x)
jederzeit gehen . Es ist weit überlegen.Ich stieß auf ein echtes Problem, bei dem es tatsächlich böse war. Im Wesentlichen hat ein Entwickler einen Verweis auf ein Objekt in einem Vektor zurückgegeben. Das war schlecht!!!
Die vollständigen Details, über die ich im Januar geschrieben habe: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
quelle
Über schrecklichen Code:
In der Tat ging der Speicherzeiger nach der Rückkehr verloren. Aber wenn Sie shared_ptr so verwenden:
Der Speicher geht nach der Rückgabe nicht verloren und wird nach der Zuweisung freigegeben.
quelle