Подтвердить что ты не робот

Ссылка lvalue стала недействительной после прохождения через функцию идентификации

Кто-нибудь объяснит, почему ссылка стала недействительной после прохождения функции "identity", foo1? Разве не "адрес" в A передается и возвращается foo1?

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;
4b9b3361

Ответ 1

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

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

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

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

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

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


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

Ответ 2

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

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