当我运行此代码时,我得到std :: bad_functon_call异常。 我无法弄清楚这个例外的原因是什么。 它由receiveCallback中的async_receive引发。 在被调用之前,receiveCallback是否从内存中清除了?
//callback on connection accepted
std::function<void(const boost::system::error_code& error, tcp::socket* socketPtr)> acceptCallback =
[this, onMessageReceivedCallback, acceptCallback](const boost::system::error_code& error, tcp::socket* socketPtr)
{
cout<<"accept: "<<error.message()<<endl;
const int bufferSize = 100;
char* message = new char[bufferSize];
//callback on message received
std::function<void(const boost::system::error_code& error,std::size_t bytes_transferred)> receiveCallback =
[message, bufferSize, socketPtr, onMessageReceivedCallback, receiveCallback](const boost::system::error_code& error,std::size_t bytes_transferred)
{
onMessageReceivedCallback(message, bytes_transferred);
socketPtr->async_receive(
boost::asio::buffer(message, bufferSize),
receiveCallback);
};
socketPtr->async_receive(
boost::asio::buffer(message, bufferSize),
receiveCallback);
//create socket for the next connection
socketPtr = new tcp::socket(io_service_);
//continue accepting connections
acceptor_.async_accept(*socketPtr, std::bind(acceptCallback, std::placeholders::_1, socketPtr));
答案 0 :(得分:2)
您的代码是未定义的行为:当lambda按值捕获receiveCallback
时,receiveCallback
尚未初始化,因此lambda获取的副本是垃圾(使用GCC 4.7我甚至得到段错误而不是{ {1}})。顺便说一下std::bad_function_call
表现出同样的问题。
一个明显的解决方案是通过引用而不是按值来捕获acceptCallback
,但是它会产生与对象生命周期相关的问题(receiveCallback
对象必须在整个持续时间内保持活动状态I / O操作,但只要退出receiveCallback
lambda就会被破坏。
这是一个鸡和蛋的情况:由于生命周期问题,通过引用捕获将无法工作,您需要通过值捕获来解决该问题,但是按值捕获会生成未初始化对象的副本,因此您需要通过引用捕获来解决那。 MEH。
请注意,accept
以其他方式不正确:您也会按值捕获receiveCallback
,这意味着每当调用lambda时,您最终都不会使用{{1}填充的缓冲区,但是使用了实例化lambda时生成的缓冲区的副本(换句话说,再次使用未初始化的垃圾)。
现在已经进行了诊断,如何修复并编写工作代码?
在我看来,完全放弃了lambda。写一个将保留message
缓冲区和boost::asio
并且具有message
和onMessageReceivedCallback
成员函数的类。
根据accept
的确切API,您可能需要在receive
个对象中“包装”您的成员函数,以获得boost::asio
可以使用的回调(std::function
是您的朋友在这里,不要忘记asio
生成的std::mem_fn
对象的第一个参数到你的类的实例。)