2013-05-04 12 views
7

Proprio nel momento in cui pensavo di comprendere il riferimento di rvalue, mi sono imbattuto in questo problema. Il codice è probabilmente inutilmente lungo, ma l'idea è abbastanza semplice. C'è una funzione main() e la funzione returnRValueRef().Come funziona il ritorno per riferimento di rvalue?

#include <iostream> 

#define NV(x) "[" << #x << "=" << (x) << "]" 
#define log(x) cout << __FILE__ << ":" << __LINE__ << " " << x << endl 

using namespace std; 

class AClass { 
public: 
    int a_; 

    AClass() : a_(0) { 
    log("inside default constructor"); 
    } 
    AClass(int aa) : a_(aa) { 
    log("inside constructor"); 
    } 
    int getInt() const { 
    return a_; 
    } 
    void setInt(int a) { 
    a_ = a; 
    } 

    AClass(AClass const & other) : a_(other.a_) { 
    log("inside copy constructor"); 
    } 

    AClass & operator=(AClass const & rhs) { 
    log("inside assignment operator" << "left value" << NV(a_) << "right value" << NV(rhs.a_)); 
    a_ = rhs.a_; 
    return *this; 
    } 

    AClass & operator=(AClass && rhs) { 
    log("inside assignment operator (rvalue ref)" << "left" << NV(a_) << "right" << NV(rhs.a_)); 
    a_ = rhs.a_; 
    return *this; 
    } 
}; 

AClass && returnRValueRef() { 
    AClass a1(4); 
    return move(a1); 
} 

int main() { 
    AClass a; 
    a = returnRValueRef(); 
} 

Va bene, mi sarei aspettato questo codice alla prima stampa "all'interno costruttore di default" (per una), poi "dentro costruttore" (per A1), e quindi il messaggio operatore di assegnamento con rhs.a_ = 4. Ma l'uscita è

testcpp/return_rvalue_ref.cpp:14 inside default constructor 
testcpp/return_rvalue_ref.cpp:17 inside constructor 
testcpp/return_rvalue_ref.cpp:39 inside assignment operator (rvalue ref)left[a_=0]right[rhs.a_=0] 

qualcuno può spiegare perché l'ultima riga nelle stampe in uscita right[rhs.a_=0] invece di right[rhs.a_=4]? Ho pensato che move() abbia appena fatto il valore di lvalue in rvalue senza cambiarne il contenuto. Ma mi manca chiaramente qualcosa.

Grazie mille per il vostro aiuto. :-)

Edit: Penso di sapere cosa potrebbe succedere. Può essere il distruttore per a1 nella funzione returnRValueRef() viene chiamato quando esce dal campo di applicazione (anche se è convertito in valore), e dopo che la posizione di memoria per a1 (o il riferimento di valore per esso) contiene roba non definita! Non sono sicuro se questo è ciò che sta accadendo, ma sembra plausibile.

risposta

18

Un riferimento di rvalue è ancora un riferimento. Nel tuo caso, stai facendo riferimento alla variabile locale che è stata distrutta. Pertanto è un comportamento indefinito accedere ai membri. Che cosa si vuole fare è quello di restituire l'oggetto:

AClass returnRValueRef() { 
    AClass a1(4); 
    return move(a1); 
} 

Tuttavia, una mossa avviene automaticamente con una variabile locale, quindi è davvero solo bisogno di fare questo:

AClass returnRValueRef() { 
    AClass a1(4); 
    return a1; 
} 
+0

Grazie per il tuo commento. Mentre hai aggiunto il tuo commento, ho anche modificato la domanda e sembra che quello che hai detto sia il problema. Grazie. (Scusa, non posso revocare la tua risposta, troppo pochi punti.) –

+0

@ YogeshwerSharma: solo un'accettazione sarebbe grandiosa, grazie! –

+0

Esiste un esempio in cui è utile il ritorno per riferimento di rvalue? Non sembra essere? :( –

Problemi correlati