Consider this code:
#include <memory>
#include <iostream>
class A
{
public:
A(int data) : data_(data)
{ std::cout << "A(" << data_ << ")" << std::endl; }
~A() { std::cout << "~A()" << std::endl; }
void a() { std::cout << data_ << std::endl; }
private:
int data_;
};
class B
{
public:
B(): a_(new A(13)) { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
std::function<void()> getf()
{
return [=]() { a_->a(); };
}
private:
std::shared_ptr<A> a_;
};
int main()
{
std::function<void()> f;
{
B b;
f = b.getf();
}
f();
return 0;
}
Here it looks like I’m capturing a_ shared pointer by value, but when I run it on Linux (GCC 4.6.1), this is printed:
A(13)
B()
~B()
~A()
0
Obviously, 0 is wrong, because A is already destroyed. It looks like this is actually captured and is used to look up this->a_. My suspicion is confirmed when I change the capture list from [=] to [=,a_]. Then the correct output is printed and the lifetime of the objects is as expected:
A(13)
B()
~B()
13
~A()
The question:
Is this behaviour specified by the standard, implementation-defined, or undefined? Or I’m crazy and it’s something entirely different?
Yes. Capturing member variables is always done via capturing
this; it is the only way to access a member variable. In the scope of a member functiona_is equivalent to(*this).a_. This is true in Lambdas as well.Therefore, if you use
this(implicitly or explicitly), then you must ensure that the object remains alive while the lambda instance is around.If you want to capture it by value, you must explicitly do so:
If you need a spec quote: