Angenommen, ich habe eine plattformübergreifende Klasse Path
wie:
Die Funktion parent()
member gibt den übergeordneten Pfad von this
path zurück und gibt (zu Recht) ein neu erstelltes Path
-Objekt zurück, das es repräsentiert.
Für eine Plattform, die Pfade auf Betriebssystemebene als UTF-8-Strings darstellt (zB Unix), erscheint es sinnvoll, dass as_utf8()
eine Referenz direkt an die interne Repräsentation path
zurückgibt, da sie bereits ist UTF-8.
Wenn ich Code habe wie:
%Vor%Beide Zeilen sind in Ordnung, weil:
my_path
bestehen bleibt, bleibt s
gültig. parent()
zurückgegeben wird, wird um const&
. So weit, so gut. Wenn ich jedoch Code wie:
%Vor% Das ist falsch , weil das temporäre Objekt, das von parent()
zurückgegeben wird nicht , seine Lebensdauer verlängert hat, weil const&
nicht tut beziehen sich auf das temporäre aber auf ein Datenelement davon. Wenn Sie versuchen, s
zu verwenden, erhalten Sie zu diesem Zeitpunkt entweder "Müll" oder einen Core-Dump. Wenn der Code stattdessen wäre:
dann wäre der Code korrekt. Es wäre jedoch ineffizient, jedes Mal, wenn diese Elementfunktion aufgerufen wird, ein temporäres Objekt zu erstellen. Die Implikation ist auch, dass no "Getter" -Elementfunktionen jemals Referenzen auf ihre Datenelemente zurückgeben sollten.
Wenn die API so belassen wird, wie sie ist, dann scheint es eine unangemessene Belastung für den Aufrufer zu sein, den Rückgabetyp von as_utf8()
zu betrachten, um zu sehen, ob er const&
zurückgibt oder nicht: if tut, dann muss der Aufrufer ein Objekt verwenden und nicht a const&
; Wenn es ein Objekt zurückgibt, kann der Aufrufer ein const&
verwenden.
Gibt es also eine Möglichkeit, dieses Problem zu lösen, so dass die API in den meisten Fällen sowohl effizient ist, noch verhindert, dass der Benutzer aus scheinbar harmlos aussehenden Code freie Referenzen erhält?
Das wurde übrigens mit g ++ 5.3 kompiliert. Es ist möglich, dass die Lebensdauer des temporären verlängert werden sollte, aber der Compiler einen Fehler hat.
Sie können zwei verschiedene Versionen von as_utf8()
erstellen, eine für lvales und eine für rvalues. Sie würden jedoch C ++ 11 benötigen.
Auf diese Weise erhalten Sie das Beste aus beiden Welten: a const&
, wenn das Objekt kein temporäres Objekt ist, und ein effizientes Objekt, wenn dies nicht der Fall ist:
Meiner Meinung nach lautet das Leitprinzip, ob eine Referenz oder ein Objekt zurückgegeben werden soll, die definierte Rolle der ursprünglichen Klasse.
d. stellt die Methode eine einfache Eigenschaft dar (argumentiert für eine Referenz, insbesondere wenn sie unveränderlich ist), oder ist es , etwas zu erzeugen?
Wenn es ein neues Objekt oder eine neue Repräsentation erzeugt, können wir vernünftigerweise erwarten, dass es ein bestimmtes Objekt zurückgibt.
Benutzer von APIs sind im Allgemeinen daran gewöhnt zu verstehen, dass Eigenschaften ihre Host-Objekte nicht überleben. Dies kann natürlich in der Dokumentation deutlich gemacht werden.
z.B.
%Vor% Ich persönlich würde das Präfix as_
in diesem Fall vermeiden, da es für mich bedeutet, dass wir eine neue Repräsentation desselben Objekts zurückgeben, wie zum Beispiel:
Tags und Links c++ data-members api-design temporary