在包含处理程序的类被破坏后,Asio调用处理程序

时间:2015-03-23 02:08:52

标签: c++ c++11 boost lambda boost-asio

我有一个类X,它在其构造函数中引用了boost::asio::io_service和一个连接的boost::astio::ip::tcp::socket。该类处理网络数据的发送和接收。

我遇到的一个问题是主代码要求X发送消息X::sendMessage(),然后主代码在下一行删除X.因此,X调用boost::asio::async_write,使用lambda作为处理程序,然后X被删除,其析构函数被调用,从而关闭套接字。没有X了。但过了一会儿boost::asio::io_service调用boost::asio::async_write调用中使用的lambda处理程序,该调用程序现在处于一个被破坏的类中,boost::system::error_code设置为"成功"。

有没有办法告诉lambda该课程被破坏了,它不应该与班级的成员和方法混在一起?

也许我可以以某种方式取消lambda处理程序在~X()中被调用?虽然写操作可能已经完成并安排了由boost::asio::io_service执行的处理程序,但是没有什么可以取消。

请注意,我无法对boost::asio::io_service对象执行任何操作,因为它通过主代码传递给X,它处理的不仅仅是网络。

class X
{
public:
    X(boost::asio::io_service &io, boost::asio::ip::tcp::socket socket)
    : io(io), socket(std::move(socket)){ }

    ~X()
    {
        if (socket.is_open()) {
            socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
            socket.close();
        }
    }

    void X::sendMessage()
    {
        boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
            [this](boost::system::error_code ec, std::size_t /*length*/)
            {
                std::cout << ec.message() << std::endl; // Success!
                // `this' is invalid though

                if (!ec) {
                    // code
                } else {
                   // code
                }
            });
    }

private:
    boost::asio::io_service &io;
    boost::asio::ip::tcp::socket socket;

修改

现在我刚刚用bool创建了一个共享指针,我将它传递给lambdas并在析构函数中设置为true,这样lambdas就可以判断对象是否已经被破坏了。这是一个肮脏的黑客,但它现在有效。从长远来看,我想有一个更优雅的解决方案。

2 个答案:

答案 0 :(得分:1)

如果您希望在asio框架引用它时确保对象保持活动状态,请将对象的共享所有权智能指针传递给lambda表达式。 E.g:

class X : public enable_shared_from_this<X>
// ...

    boost::shared_ptr<X> that = this->shared_from_this();
    boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
        [that](boost::system::error_code ec, std::size_t /*length*/)

答案 1 :(得分:0)

解决方案是将X类成员声明为共享指针(即boost::shared_ptr<X> m_x;)并将类实例传递给lambda。请参阅下面的修改后的代码。

它阻止类实例销毁,直到Asio调用lambda。

#include <boost/noncopyable.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

class X : private boost::noncopyable, public boost::enable_shared_from_this<X>
{
private:
    struct Data {
        char *data;
        size_t size;
    };
    Data m;
public:
    X(boost::asio::io_service &io, boost::asio::ip::tcp::socket socket)
        : io(io), socket(std::move(socket)){ }

    ~X()
    {
        if (socket.is_open()) {
            socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
            socket.close();
        }
    }

    void X::sendMessage()
    {
        auto self = shared_from_this();
        boost::asio::async_write(socket, boost::asio::buffer(m.data, m.size),
            [self](boost::system::error_code ec, std::size_t /*length*/)
        {
            std::cout << ec.message() << std::endl; // Success!
            // `this' is invalid though

            if (!ec) {
                // code
            }
            else {
                // code
            }
        });
    }

private:
    boost::asio::io_service &io;
    boost::asio::ip::tcp::socket socket;
};