2013-05-04 11 views
7

Właśnie wtedy, gdy myślałem, że rozumiem rvalue reference, natknąłem się na ten problem. Kod jest prawdopodobnie niepotrzebnie długi, ale pomysł jest dość prosty. Istnieje funkcja main() i funkcja returnRValueRef().Jak działa funkcja return by rvalue reference?

#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(); 
} 

Dobra, spodziewałbym ten kod pierwszego wydruku „wewnątrz domyślnego konstruktora” (dla), a następnie „wewnątrz konstruktora” (dla A1), a następnie operator przypisania wiadomości z rhs.a_ = 4. Ale wyjście jest

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] 

Może ktoś wyjaśnić, dlaczego ostatni wiersz w wydruków wyjściowych right[rhs.a_=0] zamiast right[rhs.a_=4]? Myślałem, że move() po prostu sprawia, że ​​lvalue staje się rvalue bez zmiany jego zawartości. Ale wyraźnie czegoś brakuje.

Dziękuję bardzo za pomoc. :-)

Edytuj: Myślę, że wiem, co może się dziać. Może być destruktorem dla a1 w funkcji returnRValueRef() jest wywoływany, gdy wykracza poza zasięg (nawet jeśli jest zamieniany na rwartość), a po tym miejscu pamięci dla a1 (lub referencji rvalue dla niego) zawiera niezdefiniowane rzeczy! Nie jestem pewien, czy tak się dzieje, ale wydaje się prawdopodobne.

Odpowiedz

18

Wartość odniesienia rurn jest nadal odniesieniem. W twoim przypadku odwołujesz się do zmiennej lokalnej, która została zniszczona. Dlatego nieokreślonym zachowaniem jest dostęp do członków. Co chcesz zrobić, to zwrócić przedmiot:

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

Jednak ruch odbywa się automatycznie za pomocą zmiennej lokalnej, tak naprawdę tylko trzeba to zrobić:

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

Dzięki za komentarz. Podczas dodawania komentarza edytowałem też pytanie i wydaje mi się, że to, co powiedziałeś, jest problemem. Dzięki. (Niestety, nie mogę odpowiedzieć na twoją odpowiedź, zbyt mało punktów.) –

+0

@YogeshwerSharma: po prostu akceptacja byłaby świetna, dzięki! –

+0

Czy istnieje przykład, gdzie warto zwrócić wartość referencyjna rvalue? Wygląda na to, że nie jest? :( –

Powiązane problemy