Would someone explain why the reference became invalid after going through an "identity" function, foo1? Isn't an "address" to A is passed into and returned by 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;
}
How does the problem line differ from:
const A& r = vec[0];
const A& r1 = r;
The problem is your lambda. It doesn't do what you think it does:
function<const A&(const A& r)> foo1 = [](const A& r) {
// ~~~~~~
return r;
};
Note that there's no trailing return type. That means that it's automatically deduced. Deduction never gives you a reference type, so this lambda returns an A, not an A const&. That returned temporary A is then bound to the return A const& of function's operator(). That temporary is not lifetime-extended. But the time we finish calling foo1(), we have a dangling reference to that temporary A. This is undefined behavior, which I guess with your compiler, gave you a helpful runtime error.
To fix this, you need to explicitly specify the return type:
function<const A&(const A& r)> foo1 = [](const A& r) -> A const& {
return r;
};
But even this is dangerous, since you can still pass a temporary A into this function and get a dangling reference out. No real way around that one.
The ease of falling into this trap is also LWG Issue 2813
While your function object returns const A& the lambda you provide it does not. It's return type is deduced from the return statement, which is deduced to be A. Try adding an explicit return type like this instead.
function<const A&(const A& r)> foo1 = [](const A& r) -> const A& {
return r;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With