I am learning boost::asio and C++11 simultaneously. One of my test programs, which is actually an adaptation of one of the samples given in the boost::asio tutorial is the following:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class printer {
// Static data members
private:
const static boost::posix_time::seconds one_second;
// Instance data members
private:
boost::asio::deadline_timer timer;
int count;
// Public members
public:
printer(boost::asio::io_service& io)
: timer(io, one_second), count(0) {
std::function<void(const boost::system::error_code&)> callback;
callback = [&](const boost::system::error_code&) { // critical line
if (count < 5) {
std::cout << "Current count is " << count++ << std::endl;
timer.expires_at(timer.expires_at() + one_second);
timer.async_wait(callback);
}
};
timer.async_wait(callback);
}
~printer() {
std::cout << "Final count is " << count << std::endl;
}
};
const boost::posix_time::seconds printer::one_second(1);
int main() {
boost::asio::io_service io;
printer p(io);
io.run();
return 0;
}
When I run this program, I get a segmentation fault. I do understand why I get the segmentation fault. After the constructor is done running, the constructor's callback
variable goes out of scope, and the lambda's callback
variable, which is a reference to the constructor's callback
variable, becomes a dangling reference.
So I modify the critical line with:
callback = [callback, &](const boost::system::error_code&) { // critical line
Then compile it, run it, and get a bad function call error. Again, I do understand why I get the bad function call error. Within the lambda's scope, the constructor's callback
variable has still not been assigned any value to, so it for all practical purposes is a dangling function pointer. Hence, the lambda's callback
variable, which is a copy of the constructor's callback
variable, is also a dangling function pointer.
After thinking about this problem for a while, I realized that what I truly need is that the callback be able to refer to itself using a function pointer, not a reference to a function pointer. The sample achieved this by using a named function as callback, instead of an anonymous one. However, passing named functions as callbacks is not very elegant. Is there any way to get an anonymous function have a function pointer to itself as a local variable?
There are several alternatives:
Have the lambda store a smart pointer to a dynamically allocated std::function
that stores the lambda. For example:
auto pCallback = std::make_shared<std::function<void(const boost::system::error_code&)>>();
auto callback = [=](const boost::system::error_code&) { // critical line
if (count < 5) {
std::cout << "Current count is " << count++ << std::endl;
timer.expires_at(timer.expires_at() + one_second);
timer.async_wait(pCallback.get());
}
};
*pCallback = callback;
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