2017-06-27 6 views
4

Lassen Sie uns die nächste Probe betrachten:C++ - Standard: Rückgabe per Kopie, um eine Referenz ohne RVO zu initialisieren: Gibt es eine Kopie?

struct big_type {}; 

// Return by copy 
auto factory() { return big_type{}; } 

void any_scope_or_function() { 
    big_type&& lifetime_extended = factory(); 
} 

Unter der Annahme, RVO verboten ist oder gar nicht vorhanden und in irgendeiner Art und Weise wird oder kann big_type() kopiert werden? Oder wird die Referenz direkt an die temporäre innerhalb der return Anweisung gebaut werden?

Ich möchte sicher sein, dass der big_type Destruktor nur einmal aufgerufen wird, wenn any_scope_or_function endet.

Ich benutze C++ 14, falls sich das Verhalten zwischen den Standardversionen geändert hat.

+0

@NathanOliver Ich habe vergessen, diesen Compiler-Schalter herauszunehmen. Whoopsies. –

+0

Außerdem kann ich C++ 17 nicht verwenden; C++ höchstens 14. –

+1

@ Peregring-lk aber für den Rekord .. dies in C++ 17 geändert, die nicht mehr Kopie Elision hier erfordert. –

Antwort

8

Vorausgesetzt, es gibt keine RVO/Kopie elison dann in

auto factory() { return big_type{}; } 

big_type{} eine temporäre big_type erstellen wird. Dieses Objekt wird dann verwendet werden, um kopieren initialisieren das Objekt, das die Funktion zurückgibt. Dies bedeutet, dass das Objekt, das Sie in der Funktion erstellen, konstruiert und zerstört wird.

Mit

big_type&& lifetime_extended = factory(); 

die rvalue Referenz wird die Lebensdauer der Funktionen erweitern zurückkehren, so dass wir insgesamt einen Standard Konstruktoraufruf, ein Kopieren/Verschieben Konstruktoraufruf und zwei destructor Anrufe sehen.

Wenn wir nun

ändern
auto factory() { return big_type{}; } 

zu

big_type factory() { return {}; } 

dann sind wir nicht mehr ein Objekt in der Fabrik zu schaffen. das Rückgabeobjekt mit {} gibt uns insgesamt einen Standardkonstruktor Anruf und einen Destruktoraufrufs direkt initialisiert

3

Oder wird der Verweis direkt auf die temporären konstruiert innerhalb der return-Anweisung gebunden werden?

Nein, wird es nicht sein. Genau darum geht es bei (N) RVO und das wollen Sie explizit nicht.

Was jedoch versucht wird, ist die Verwendung des Move-Konstruktors Ihrer big_type, die technisch keine Kopie ist. Es verletzt: "big_type Destruktor wird nur einmal aufgerufen, wenn any_scope_or_function endet" obwohl es zweimal aufgerufen wird.

GCC/Clang hat einen netten Compiler-Schalter: -fno-elide-constructors, der (N) RVO deaktiviert, die für zukünftige Referenz verwendet werden können. Momentan ist here ein Test, der diese Option aktiviert hat und einen doppelten Destruktoraufruf anzeigt.

Verwandte Themen