This question already has an answer here:
Repeatable example:
#include <iostream>
#include <boost/asio/io_service.hpp>
boost::asio::io_service io_service;
void test1(int t_a)
{
std::cout << "in test1: t_a = " << t_a << std::endl;
}
void test2(int t_a)
{
std::cout << "in test2: t_a = " << t_a << std::endl;
io_service.post([&t_a]()
{
std::cout << "in test2 post lambda: t_a = " << t_a << std::endl;
test1(t_a);
});
}
int main(int, char**)
{
int a = 42;
for (;;) {
try
{
test2(a);
io_service.run();
break;
}
catch (std::exception & e)
{
}
}
}
Output:
in test2: t_a = 42
in test2 post lambda: t_a = 16451253
in test1: t_a = 16451253
Press any key to continue . . .
Why is that? Capturing by value is working as I expect it to, but why does capturing by reference behave like this?
Note int
here is only for example, consider any big object which is bad to pass by value (expendable copy, for example)
Why if I declare test1
and test2
as test1(const int& t_a)
and test2(const int& t_a)
all is working correctly then?
The reference of
t_a
is valid only invoid test2(int t_a)
scope. Capture by value in your case.Unfortunately C++ doesn't provide a garbage collector (yet) and therefore the use of closures is somewhat impaired.
You can capture by reference (thus for example having multiple closures referencing the same captured object) but the lifetime for the object must be guaranteed independently from the lifetime of the closures; in other words if a lambda capturing a variable by reference survives the referenced object and is called when the object has already been destroyed then you get in the usual "undefined behavior" realm.
This is what happens in your code: the captured variable is a parameter of the function and when the closure is called it has already been destroyed.
A solution is either capture by value (in this case the capture object is copied inside the closure and you don't have a lifetime problem) or use for example a reference-counted smart pointer like
std::shared_ptr
to a free-store allocated object to ensure that as long as the closure survives the referenced (pointed-to) object also survives.Because the reference is dangling. It refers to a function argument, which will cease to exist as soon as the function returns. The function returns before your asynchronous code runs.
Just capture
t_a
by value, surely?