2017-10-28 3 views
2

Betrachten wir eine Funktion haben, die von Wert zurückgibt:Verweis auf r-Wert (Adresse von r-Wert)

int func() { 
    int x = 10; // create local variable x with value of 5 
    return x; // create temporary copy of x which is returned, local variable x is destroyed 
} 

int main() 
{ 
    int y = func(); // temporary copy of x is copied to y, when it hits`;` the temporary object is destroyed 
    return 0; 
} 

mich korrigieren, wenn ich in etwas falsch bin, was ich oben in den Kommentaren gesagt.

Jetzt können wir die Lebensdauer eines temporären Objekts verlängern, indem wir uns konstant darauf beziehen.

int main() 
{ 
    const int & y = func(); // now the temporary object (R-value) is not destroyed when it hits `;` thus the life time is lenghtened. 
    return 0; 
} 

Die Frage ist: Da ich einen konstanten Verweis auf temporäres Objekt geschaffen, die zerstört werden sollen, bedeutet es, dass cout << &y << endl die Adresse dieses temporären Objekts gedruckt wird, da Referenz nur „alias“? Auch wo sind diese temporären Objekte (R-Werte) gespeichert im Speicher (ich verwendete primitiven Typ int, aber es könnte Klasse sein)?

+3

Wo Provisorien gespeichert sind, können Sie nichts wissen. Das ist Implementierung definiert. –

+3

"wo sind diese temporären Objekte (R-Werte) gespeichert?" Warum kümmert es dich überhaupt? – DimChtz

+0

@JesperJuhl Nun, dann die Adresse, die 'cout << & y << endl;' ist nicht die Adresse dieses temporären Objekts? Was stellt diese Adresse dann dar? – kvway

Antwort

2

Wie bereits in den Kommentaren erwähnt, wird durch das Vornehmen einer const-Referenz (oder rvalue-Referenz) auf ein temporäres Objekt dessen Lebensdauer auf diejenige des Referenzwerts verlängert.

Auch wo sind diese temporären Objekte (R-Werte) im Speicher gespeichert (i verwendet primitiven Typ int, aber es könnte Klasse sein)?

Dies ist nicht durch den Standard spezifiziert. Sie können jedoch einfach die häufigsten Compiler nachsehen, was sie tun werden. Beginnend mit GCC, ohne Optimierungen, werden Sie

func(): 
    push rbp 
    mov rbp, rsp 
    mov DWORD PTR [rbp-4], 10 
    mov eax, DWORD PTR [rbp-4] 
    pop rbp 
    ret 
main: 
    push rbp 
    mov rbp, rsp 
    sub rsp, 16 
    call func() 
    mov DWORD PTR [rbp-12], eax 
    lea rax, [rbp-12] 
    mov QWORD PTR [rbp-8], rax 
    mov eax, 0 
    leave 
    ret 

https://godbolt.org/g/8wPQqx

erhalten also der Rückgabewert wird innerhalb der Funktion in EAX-Register geschoben und sobald es zurückgibt, wird der Wert auf den Stapelrahmen geschoben von main(), als hätten Sie die Variable in der Hauptfunktion erstellt. Sie werden ähnliche Ergebnisse mit anderen Compilern finden. Wenn auf Optimierungen drehen, na ja, wird die offensichtliche passieren: der Compiler die Funktion sieht nur etwas konstanter Wert zurückgibt und elides es ganz aus:

func(): 
    mov eax, 10 
    ret 
.LC0: 
    .string "%i" 
main: 
    sub rsp, 24 
    mov edi, OFFSET FLAT:.LC0 
    xor eax, eax 
    lea rsi, [rsp+12] 
    mov DWORD PTR [rsp+12], 10 
    call printf 
    xor eax, eax 
    add rsp, 24 
    ret 

Hier habe ich einige printf hinzugefügt() aufrufen, dass ausgeben wird die Adresse der temporty st das Programm ist nicht ganz trivial. So erstellt es die Funktion, wird es aber nicht stören, es aufzurufen, und schreibt einfach 10 erneut in ein Leerzeichen im lokalen Stapelrahmen. Wenn Sie es nur nach Wert verwenden, wird es einfach in ein Register eingetragen, da keine Adresse benötigt wird.