C ++ - Universalreferenz im Konstruktor und Rückgabewertoptimierung (rvo)

8

Warum findet die rvalue-Optimierung nicht in Klassen mit Konstruktoren mit universellen Referenzargumenten statt?

Ссылка

%Vor%

Ausgabe:

%Vor%     
tower120 24.07.2014, 04:27
quelle

1 Antwort

9

Ich glaube, dass das Problem die Instanziierung von

ist %Vor%

sind, soweit es die Sprache betrifft, keine copy / move-Konstruktoren, und daher können Aufrufe an sie vom Compiler nicht gelöscht werden. Aus §12.8 [class.copy] / p2-3, Hervorhebung hinzugefügt und Beispiele weggelassen:

  

Ein Nicht-Template-Konstruktor für die Klasse X ist ein Kopierkonstruktor if   Der erste Parameter ist vom Typ X& , const X& , volatile X& oder const volatile X& .   und entweder gibt es keine anderen Parameter oder sonst alle   Andere Parameter haben Standardargumente (8.3.6).

     

Ein Nicht-Template-Konstruktor für die Klasse X ist ein move-Konstruktor if   Der erste Parameter ist vom Typ X&& , const X&& , volatile X&& oder    const volatile X&& , und entweder gibt es keine anderen Parameter oder sonst alle   Andere Parameter haben Standardargumente (8.3.6).

Mit anderen Worten, ein Konstruktor, der eine Vorlage ist, kann niemals ein Kopier- oder Verschiebekonstruktor sein.

Die Rückgabewert-Optimierung ist ein Spezialfall der Kopie-Elision, die als (§12.8 [class.copy] / p31) beschrieben wird:

  

Wenn bestimmte Kriterien erfüllt sind, darf eine Implementierung ausgelassen werden   die Kopie / Move-Konstruktion eines Klassenobjekts, selbst wenn der Konstruktor   ausgewählt für die Kopier- / Verschiebeoperation und / oder den Destruktor für die   Objekt haben Nebenwirkungen.

Dies ermöglicht Implementierungen, "Konstruktion kopieren / verschieben" zu ermöglichen; Das Konstruieren eines Objekts mit etwas, das weder ein Kopierkonstruktor noch ein Move-Konstruktor ist, ist keine "Konstruktion kopieren / verschieben".

Da C über einen benutzerdefinierten Destruktor verfügt, wird kein impliziter Move-Konstruktor generiert. Daher wählt die Überladungsauflösung den Vorlagenkonstruktor mit Args abgeleitet als C , was eine bessere Übereinstimmung als der implizite Kopierkonstruktor für rvalues ​​ist. Der Compiler kann jedoch keine Aufrufe an diesen Konstruktor ausgeben, da er Nebeneffekte aufweist und weder ein Kopierkonstruktor noch ein Verschiebungskonstruktor ist.

Wenn der Vorlagenkonstruktor stattdessen

ist %Vor%

Dann kann es nicht mit Args = C instanziiert werden, um einen Kopierkonstruktor zu erzeugen, da dies zu einer unendlichen Rekursion führen würde. Es gibt eine spezielle Regel im Standard, die solche Konstruktoren und Instanziierungen verbietet (§12.8 [class.copy] / p6):

  

Eine Deklaration eines Konstruktors für eine Klasse X ist schlecht formatiert, wenn seine   Der erste Parameter ist vom Typ (optional cv-qualifiziert) X und entweder   Es gibt keine anderen Parameter oder alle anderen Parameter   Standardargumente. Eine Elementfunktionsvorlage wird niemals instanziiert   eine solche Konstruktorsignatur erzeugen.

In diesem Fall wäre also der einzige ausführbare Konstruktor der implizit definierte Kopierkonstruktor, und Aufrufe an diesen Konstruktor können weggelassen werden.

Wenn wir anstelle den benutzerdefinierten Destruktor aus C entfernen und eine weitere Klasse hinzufügen, die bei% co_de verfolgt wird Der Destruktor von% wird stattdessen aufgerufen:

%Vor%

Wir sehen nur einen Aufruf von C destructor, was darauf hinweist, dass nur ein D -Objekt konstruiert ist. Hier wird der Bewegungskonstruktor von C implizit generiert und durch die Überladungsauflösung ausgewählt, und Sie sehen, dass RVO erneut eingreift.

    
T.C. 24.07.2014, 04:59
quelle