C++ lambda自传递异常

标签 c++ exception lambda boost-asio

当我运行此代码时,出现 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,并且具有acceptreceive成员函数。

根据 boost::asio 的具体 API,您可能需要将成员函数“包装”在 std::function 对象中以获取 asio 可以使用(std::mem_fn 是你的 friend ,不要忘记 std::bind 结果 std 的第一个参数::function 对象到您的类的实例)。

关于C++ lambda自传递异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16641335/

相关文章:

java - 为什么添加 throws InterruptedException 会为 Runnable 的实现创建编译错误

haskell - 如何比较两个函数的等价性,如 (λx.2*x) == (λx.x+x)?

php - 无法破坏事件的 lambda 函数

c++ - 使用 C++ 对象的指针指向另一个 C++ 对象,从 Lua 修改成员变量

c# - 通过示例规划编程项目(C# 或 C++)

jquery - 当未找到元素时,是否可以让 jQuery 抛出异常?

mysql - 使用 lambda 时出现 Rails 3 作用域关联错误

Python3 类型错误 : a bytes-like object is required, 不是 'str'

c++ - 使用 Qt MultiMedia 和 Widgets 播放网络流媒体视频

java - 使用 DeltaSpike Security 时出现 ClassCastException?