2016-07-14 2 views
-1

Es gibt eine komplexe Klasse mit Konstruktor, die eine Nachricht für RVO druckt.
Ich habe Complex Operator + Methode in Gtest getestet.
Wenn RVO aufgetreten ist, druckt "Complex !!" Nachrichten für 3 mal.
Aber es gibt "Complex !!" Nachrichten für 5 mal.
RVO ist nicht aufgetreten, denke ich.
Ich habe diesen Code von C++ 98 und C++ 11
kompiliert Warum tritt RVO nicht auf?
Warum gilt RVO nicht in diesem Code

#include <stdio.h> 

class Complex { 
    friend Complex operator+(const Complex&, const Complex&); 
public: 
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { printf("\nComplex!!\n");} 

    Complex(const Complex& c) : real(c.real), imag(c.imag) {} 

    Complex& operator=(const Complex& c) { 
     real = c.real; 
     imag = c.imag; 

     return *this; 
    } 

    ~Complex() {} 
private: 
    double real; 
    double imag; 
}; 

Complex operator+(const Complex& lhs, const Complex& rhs) 
{ 
    return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag); 
} 

int main() 
{ 
    Complex a(1.0), b(2.0), c; 

    for (int i = 0; i < 2; i++) { 
     c = a + b; 
    } 
} 
+6

Es gibt 5 Konstruktoraufrufe: je einer für die Initialisierung von 'a',' b' und 'c', und einer für jeden Aufruf von' operator +'. Warum glaubst du, dass es eine andere Nummer geben würde? Welche sollte deiner Meinung nach nicht passieren? – immibis

+3

RVO elides Aufrufe zum Kopieren von Konstruktoren und Verschieben von Konstruktoren, nicht andere. Dein Code sagt dir nichts über RVO. –

+1

Es könnte auftreten für "Complex c = a + b;". Jetzt haben Sie nur eine Aufgabe, die nicht anwendbar ist. –

Antwort

7

RVO ist keine Optimierung, um Objekte zu verhindern konstruiert - es ist eine Optimierung, um unnötige zusätzliche Kopien oder Bewegungen zu vermeiden.

Ihr Beispiel baut drei Objekte (a, b und c) und dann zwei Konstruieren mehr (a+b zweimal in der Schleife). Diese Objekte alle müssen konstruiert werden, gibt es keinen Weg, um das zu optimieren - der Compiler kann nicht auseinander brechen die Complex() temporäre Initialisierung innerhalb operator+ und entpacken Sie es in die Zuordnungen zu real und imag innerhalb operator=.

Wenn Sie Ihren Kopier- und Bewegungskonstruktor instrumentiert hätten, würden Sie sehen, dass sie in Ihrem Beispiel nicht aufgerufen wurden. Aber sie hätten es sein können. Das innerhalb von operator+() erstellte temporäre Objekt wird konzeptionell in die Rückgabe der Funktion verschoben, bevor es in Complex::operator=() an die Referenz gebunden wird. Es ist , dass bewegen, die über RVO ist, und es ist diese Bewegung, die Sie sehen würden, wenn Sie mit -fno-elide-constructors kompiliert.

+0

Ich möchte das temporäre innerhalb Operator +() erstellt erstellen. In diesem Fall, wie kann ich dieses temporäre mit RVO entfernen? –

+0

@GyeongWonDo Es ist nicht etwas, was du * tun * musst. Wenn Sie 'Complex d = a + b;' geschrieben hätten, würde das keine Kopie/Bewegung ausführen - es würde das temporäre In-Place in 'd' konstruieren. Aber 'operator +()' muss ein Objekt konstruieren. – Barry

+0

Ich habe überprüft, dass der Kopierkonstruktor mit der Option -fno-elide-constructors aufgerufen wird. Aber Copy-Konstruktor wird nicht ohne -fno-elide-constructors-Optionen aufgerufen. Sie meinen, das ist RVO? –

7

Rückgabewert Optimierung ist eine Form von Kopie elision. Vereinfacht ausgedrückt ist es eine Optimierung, die das Kopieren von Objekten vermeidet. Es vermeidet nicht die Erzeugung von Objekten auf andere Weise.

Sie können überprüfen, ob RVO angewendet wurde, indem Sie die Nebeneffekte des Kopier- und des Move-Konstruktors beobachten.

Ihr Kopierkonstruktor hat keine Nebenwirkungen, daher kann nicht beobachtet werden, ob RVO angewendet wurde oder nicht.

Wenn RVO aufgetreten ist, zwei "Complex !!" Nachrichten im Aufruf von Operator + sollten nicht gedruckt werden.

Nein. Diese Nachrichten werden im regulären Konstruktor der Klasse (nicht Copy) gedruckt. RVO hat keinen Einfluss darauf, wie oft ein regulärer Konstruktor aufgerufen wird.

+0

Danke, ich schreibe einige Nachrichten (Seiteneffekte) in den Kopierkonstruktor. Und ich überprüfte Kopie Konstruktor wird aufgerufen oder nicht mit -fno-elide-Konstruktoren Option –

Verwandte Themen