2017-02-10 4 views
33

Может кто-нибудь объяснить, почему ссылка стала недействительной после прохождения функции «identity», foo1? Разве не «адрес» A передан и отправлен foo1?Ссылка lvalue стала недействительной после прохождения через функцию идентификации

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; 
} 

Как проблема линия отличается от:

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

Я попытался с vs2015, и ваш код работает хорошо. – alangab

+0

@alangab не работал в VS2013. –

+8

Я думал, что лямбда называется «дураком». Это было глупо. –

ответ

43

Проблема заключается в вашей лямбда. Он не делает то, что вы думаете:

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

Обратите внимание, что нет обратного типа возврата. Это означает, что он автоматически выводится. Вычет никогда не дает вам ссылочного типа, поэтому эта лямбда возвращает A, а не A const&. Полученное временное значение A затем привязано к обратному A const& от function's operator(). Это временное не продлевается на всю жизнь. Но когда мы закончим звонить foo1(), у нас есть болтающаяся ссылка на этот временный A. Это неопределенное поведение, которое, как я полагаю, с вашим компилятором дало вам полезную ошибку времени выполнения.

Чтобы это исправить, нужно явно указать тип возвращаемого значения:

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

Но даже это опасно, так как вы можете пройти временныеA в эту функцию и получить оборванную ссылку из. Никакого реального пути вокруг этого.


Легкость попадания в эту ловушку также LWG Issue 2813

+4

Уг, это неприятная ловушка :( –

+2

Также полезно использовать '-> auto &&' для сохранения хотя бы некоторого вычитания типа возврата. – Predelnik

12

В то время как ваш function объект возвращает const A& лямбда вы обеспечиваете его нет. Тип возвращаемого значения выводится из оператора return, который выводится как A. Вместо этого попробуйте добавить явный тип возвращаемого значения.

function<const A&(const A& r)> foo1 = [](const A& r) -> const A& { 
    return r; 
}; 
Смежные вопросы