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