2017-02-10 4 views
33

Czy ktoś mógłby wyjaśnić, dlaczego odwołanie się nieważne po przejściu przez funkcję "tożsamości", foo1? Czy adres "A" nie jest przekazywany i zwracany przez foo1?Odwołanie do lvalue stało się nieprawidłowe po przejściu przez funkcję identyfikacji

struct A { 
    A(int x) : x_(x) {} 
    int x_; 
}; 

int main() { 

    function<const A&(const A& r)> foo1 = [](const A& r) { 
     return r; 
    }; 

    vector<A> vec{1, 2, 3}; 
    cout << foo1(vec[0]).x_ << endl; // RUNTIME ERROR 

    return 0; 
} 

jaki sposób różnią się od linii Problem:

const A& r = vec[0]; 
const A& r1 = r; 
+0

Próbowałem z vs2015 i kod działa dobrze. – alangab

+0

@alangab nie działał w VS2013. –

+8

Myślałem, że lambda została nazwana "głupcem". To było głupie. –

Odpowiedz

43

Problem stanowi Twoja lambda. Nie robi to, co myślisz:

function<const A&(const A& r)> foo1 = [](const A& r) { 
//            ~~~~~~ 
    return r; 
}; 

Należy pamiętać, że nie istnieje żaden zwrotny typ powrotu. Oznacza to, że jest on automatycznie dedukowany. Dedukcja nigdy nie podaje typu referencyjnego, więc ta wartość lambda zwraca wartość A, a nie A const&. Ten zwrócony tymczasowy A jest następnie powiązany z powrotem A const& z function 's . To tymczasowe nie jest przedłużone na całe życie. Ale gdy kończymy połączenie foo1(), mamy zwisające odwołanie do tego tymczasowego A. To jest niezdefiniowane zachowanie, które, jak sądzę, z twoim kompilatorem, dało ci pomocny błąd runtime.

Aby rozwiązać ten problem, trzeba jednoznacznie określić typ zwracanej:

function<const A&(const A& r)> foo1 = [](const A& r) -> A const& { 
    return r; 
}; 

Ale nawet to jest niebezpieczne, ponieważ nadal można przekazać tymczasowyA do tej funkcji, a otrzymasz dangling odwołania się. Nie ma prawdziwego sposobu obejścia tego.


Łatwość należących do tej pułapki jest również LWG Issue 2813

+4

Ugh, to paskudna pułapka :( –

+2

Może być również użyteczne użycie '-> auto &&' do zachowania przynajmniej części odjęcia typu zwrotu. – Predelnik

12

Podczas gdy obiekt function zwraca const A& lambda podać go nie ma. Jego typ powrotu wywodzi się z instrukcji return, która jest określona jako A. Spróbuj zamiast tego dodać jawny typ zwracany.

function<const A&(const A& r)> foo1 = [](const A& r) -> const A& { 
    return r; 
}; 
Powiązane problemy