2016-06-24 28 views
3

Ich habe in this Artikel über NRVO gesucht.verständigen Kopie Konstruktor Aufrufe und benannte Rückgabewert-Optimierung

class RVO 
    { 
    public: 
    RVO(){ 
      printf("I am in constructor\n"); } 
    RVO(const RVO& c_RVO) { 
      printf("I am in copy constructor\n"); } 
    ~RVO(){ 
      printf("I am in destructor\n"); } 
    int mem_var; 
    }; 
    RVO MyMethod(int i) 
    { 
    RVO rvo; 
    rvo.mem_var = i; 
    return (rvo); 
    } 
    int main() 
    { 
     RVO rvo; 
     rvo=MyMethod(5); 
    } 

Die Ausgabe ist die folgende auf Visual Studio und das ist, wie ich es verstehe

I am in constructor  // main rvo construction 
I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying temporary in MyMethod 
I am in destructor  //Destroying rvo of main 

Wenn stattdessen i die Haupt als

int main() 
{ 
    RVO rvo = MyMethod(5); 
    return 0; 
} 

Der Ausgang ist der Schreib folgende und wie verstehe es

I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying rvo of main 

Warum wird temporär in Mymethod in der zweiten Version nicht zerstört?

Warum ist Copykonstruktor nicht in RVO rvo = MyMethod(5); .Ich genannt denken Copy-Konstruktor sollte zweimal in der zweiten Version aufgerufen werden, eine für die temporäre innerhalb Mymethod und die andere geschaffen für RVO rvo = MyMethod(5); ich einige nennen wissen elided.Can jemand sein kann immer bitte Hilfe bei der Erklärung dieser Anrufe.

EDIT: Mit return rvo statt return (rvo) ändert sich die Ausgabe als

Erster Fall

I am in constructor 
I am in constructor 
I am in destructor 
I am in destructor 

zweiten Fall

I am in constructor 
I am in destructor  

Ich denke, wenn ich die Klammer entfernt, dann NRVO tritt in Aber ich interessiere mich mehr für die erste Ausgabe, wenn es keine Optimierung gibt

+0

Es gibt etwas Fischiges über die Ausgabe des zweiten Beispiels. Jeder resonierbare Compiler sollte RVO anwenden, so dass Sie keinen Kopierkonstruktoraufruf erhalten sollten. –

+0

@ Cheersandhth.-Alf siehe http://ideone.com/S5Kqn9 –

+0

Entfernen Sie die Klammer um den Rückgabeausdruck. –

Antwort

0

UPDATE: die Ausgabe des aktualisierten Programms Adressierung mit return rvo statt return (rvo);

I am in constructor 
I am in constructor 
I am in destructor 
I am in destructor 

Der Grund, warum Sie dies sehen, ist, dass beide Objekte (MyMethod::rvo und main::rvo) Standardkonstruktion unterziehen, dann die letztere zugewiesen als separate Aktion, aber Sie protokollieren das nicht.


Sie können ein viel besseres Gefühl dafür, was durch Ausgabe der Adressen der Objekte vor sich geht, und die this Zeigerwerte als Funktionen aufgerufen werden: wird

#include <cstdio> 
#include <iostream> 
class RVO 
    { 
    public: 
    RVO(){ 
      printf("%p constructor\n", this); } 
    RVO(const RVO& c_RVO) { 
      printf("%p copy constructor, rhs %p\n", this, &c_RVO); } 
    ~RVO(){ 
      printf("%p destructor\n", this); } 
    int mem_var; 
    }; 
    RVO MyMethod(int i) 
    { 
    RVO rvo; 
    std::cout << "MyMethod::rvo @ " << &rvo << '\n'; 
    rvo.mem_var = i; 
    return (rvo); 
    } 
    int main() 
    { 
     RVO rvo=MyMethod(5); 
     std::cout << "main::rvo @ " << &rvo << '\n'; 
    } 

Der Ausgang auch davon abhängen, ob Sie mit Optimierungen kompilieren; Sie verknüpfen mit Microsoft-Dokumentation, also verwenden Sie möglicherweise den Microsoft-Compiler - versuchen Sie cl /O2.

Warum ist temporäre in Mymethod in der zweiten Version nicht zerstört?

Es gab keine temporäre dort - das Objekt in main wurde direkt kopiert. Treten Sie durch sie:

002AFA4C constructor 
MyMethod::rvo @ 002AFA4C // MyMethod::rvo's constructed 

002AFA70 copy constructor, rhs 002AFA4C // above is copied to 2AFA70 
002AFA4C destructor  // MyMethod::rvo's destructed 
main::rvo @ 002AFA70  // turns out the copy above was directly to main::rvo 
002AFA70 destructor  // main::rvo's destruction 

[Alf Kommentar unten] „direkt kopieren konstruierten“ mir nicht ganz sinnvoll ist. Ich denke, die OP bedeutet RVO lokale Variable

die verstärkte Ausgabe von der ersten Version des Programms Betrachten (ohne Optimierung):

002FF890 constructor // we find out this is main::rvo below 
002FF864 constructor // this one's MyMethod::rvo 
MyMethod::rvo @ 002FF864 
002FF888 copy constructor, rhs 002FF864 // 2FF888 is some temporary 
002FF864 destructor // there goes MyMethod::rvo 
002FF888 destructor // there goes the temporary 
main::rvo @ 002FF890 
002FF890 destructor // and finally main::rvo 

Wenn wir das in an den Ausgang des OP zurückbinden und Anmerkungen ...

I am in constructor  // main rvo construction 
I am in constructor  //MyMethod rvo construction 
I am in copy constructor //temporary created inside MyMethod 
I am in destructor  //Destroying rvo in MyMethod 
I am in destructor  //Destroying temporary in MyMethod 
I am in destructor  //Destroying rvo of main 

Das OP (korrekt) bezieht sich auf das kopierte Objekt als temporäres Objekt. Wenn ich von der zweiten Version des Programms sage "Da war keine temporäre da - das Objekt im Haupt wurde direkt kopiert-konstruiert." - Ich meine, dass es kein temporäres Äquivalent zu dem ersten Programm gibt, das wir oben direkt analysiert haben, und stattdessen ist es main::rvo, das aus MyMethod::rvo copy-constructed ist.

+0

"direkt kopieren-konstruiert" ist für mich nicht ganz sinnvoll. Ich denke, das OP bedeutet die 'rvo' lokale Variable. –

+1

@ Cheersandthth.-Alf: Ich gehe in der letzten Bearbeitung durch - hoffe, das ist klar. Prost. –

+0

@TonyD Die Ausgabe für den zweiten Fall, den Sie erwähnt haben, zeigt, dass eine Optimierung durchgeführt wurde. richtig? Ich lief den zweiten Fall mit der Optimierung aus, sogar dann bekomme ich die gleiche Ausgabe (mit etwas Optimierung). Wenn die Optimierung aus ist, sollte es zwei Kopie Konstruktor calls.Right geben? –

0

Der erste Aufruf des Deskuktors stammt von der Zerstörung des RVO in main. Das zuerst erstellte Objekt muss gelöscht werden. Es ist keine Kopierzuweisung, sondern eine Kopierkonstruktion.