Lebensdauerverlängerung von Datenelementen und API-Design von Provisorien

8

Angenommen, ich habe eine plattformübergreifende Klasse Path wie:

%Vor%

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:

  • Unter der Annahme, dass my_path bestehen bleibt, bleibt s gültig.
  • Die Lebensdauer des temporären Objekts, das von parent() zurückgegeben wird, wird um const& .
  • erweitert

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:

%Vor%

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.

    
Paul J. Lucas 24.08.2016, 16:07
quelle

2 Antworten

7

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:

%Vor%     
Rakete1111 24.08.2016, 16:14
quelle
1

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:

%Vor%     
Richard Hodges 24.08.2016 16:36
quelle