当我运行此代码时,出现 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));
最佳答案
您的代码是未定义的行为:当 lambda 按值捕获 receiveCallback
时,receiveCallback
尚未初始化,因此 lambda 获取的拷贝是垃圾(使用 GCC 4.7 我什至得到段错误而不是 std::bad_function_call )。顺便说一下,acceptCallback
也存在同样的问题。
一个明显的解决方案是通过引用而不是值捕获 receiveCallback
,但是这样会带来与对象生命周期相关的问题(receiveCallback
对象必须在 I/O 操作的整个持续时间内保持事件状态,但一旦退出 accept
lambda,它就会被销毁。
这是先有鸡还是先有蛋的情况:由于生命周期问题,通过引用捕获将不起作用,您需要通过值捕获来解决这个问题,但是通过值捕获会生成未初始化对象的拷贝,因此您需要通过引用捕获来解决这个问题那。嗯。
请注意,receiveCallback
在另一种方式上是不正确的:您也通过值捕获消息
,这意味着每当调用 lambda 时,您最终都不会得到缓冲区由 boost::asio
填充,但使用 lambda 实例化时创建的缓冲区拷贝(换句话说,又是未初始化的垃圾)。
既然诊断已经完成,如何解决这个问题并编写工作代码?
在我看来,完全放弃 lambda 表达式。编写一个类来保存您的消息
缓冲区和onMessageReceivedCallback
,并且具有accept
和receive
成员函数。
根据 boost::asio
的具体 API,您可能需要将成员函数“包装”在 std::function
对象中以获取 asio
可以使用(std::mem_fn
是你的 friend ,不要忘记 std::bind
结果 std 的第一个参数::function
对象到您的类的实例)。
关于C++ lambda自传递异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16641335/