Reputation: 79441
Suppose I have the following.
struct A
{
int x;
std::function<int()> f1() { return [=](){ return x; }; }
std::function<int()> f2() { return [=](){ return this->x; }; }
std::function<int()> f3() { return [this](){ return x; }; }
std::function<int()> f4() { return [this](){ return this->x; }; }
std::function<int()> f5()
{
int temp = x;
return [=](){ return temp; };
}
}
And now I have the following code.
auto a = std::make_shared<A>();
a->x = 5;
std::function<int()> f = a.f#();
a.reset();
int x = f();
where the f#
is referring to any of f1, f2, f3, f4, f5
.
These functions are exhibiting behavior in one of two sets:
f5
), ornullptr
(f1, f2, f3, f4
).I understand that this is because some are capturing "this
" in the member function of A
, either implicitly or explicitly.
What is the formal rule that's determining behavior 1 or 2?
I spent a while dealing with a bug that was caused by something similar to f1
, thinking it would capture x
and never considering it would capture this
, so I figured it would be useful to get this documented.
Upvotes: 7
Views: 269
Reputation: 473272
There is no formal rule that determines this behavior. Because this behavior is undefined.
Your lambdas are accessing an object that doesn't exist. You can't capture a member variable directly by value; you always capture them by this
. Which means you're capturing them by reference. Once the object is deleted, any attempt to access that deleted object results in undefined behavior.
The exception to this is f5
, which should return a consistent value, guaranteed. It's completely disconnected from the originating object.
Upvotes: 8