我正在学习boost :: asio和C++ 11.我的一个测试程序,实际上是对boost :: asio教程中给出的一个示例的改编,如下所示:
#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;
}
Run Code Online (Sandbox Code Playgroud)
当我运行这个程序时,我得到一个分段错误.我明白为什么会出现分段错误.构造函数完成运行后,构造函数的callback变量超出范围,lambda的callback变量(对构造函数callback变量的引用)变为悬空引用.
所以我修改了关键线:
callback = [callback, &](const boost::system::error_code&) { // critical line
Run Code Online (Sandbox Code Playgroud)
然后编译它,运行它,并得到一个错误的函数调用错误.再次,我明白为什么我得到了错误的函数调用错误.在lambda的范围内,构造函数的callback变量仍未被赋值给任何值,因此它实际上是一个悬空函数指针.因此,lambda的callback变量是构造函数callback变量的副本,也是一个悬空函数指针.
在考虑了这个问题一段时间后,我意识到我真正需要的是回调能够使用函数指针引用自身,而不是对函数指针的引用.该示例通过使用命名函数作为回调而不是匿名函数来实现此目的.但是,将命名函数作为回调传递并不是很优雅.有没有办法让一个匿名函数有一个函数指针将自己作为一个局部变量?
有几种选择:
让lambda存储一个指向std::function存储lambda 的动态分配的智能指针.例如:
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;
Run Code Online (Sandbox Code Playgroud)