异步回调中的 C++ boost-asio-network,哪个更好?使用 lambda 或 boost::bind()

C++ boost-asio-network in async callback, which one is better ? using lambda or boost::bind()

C++ lambda 让我感到困惑。

为异步读取绑定函数。

template<typename T>
class connection
    : public boost::enable_shared_from_this<connection<T>>
    , boost::noncopyable
{
public:
    using err = boost::system::error_code;

protected:
    boost::asio::ip::tcp::socket socket_;
...

// completion function
// read until meet '\n'
size_t on_read_completion(const err& error, size_t bytes) 
{
    if (error) { return 0; }

    bool found = std::find(read_buffer_, read_buffer_ + bytes, '\n') < read_buffer_ + bytes;
    return found ? 0 : 1;
}

// read message
void on_read(const err& error, size_t bytes)
{
    if (!started_) { return; }

    if (error)
    {
        std::cout << "[ERROR] async_read " << error.message();
        stop();
    }

    std::string msg(read_buffer_, bytes);
    // handle received message
    on_message(msg);
}

这是异步 read() 函数。

void read()
{
    if (!socket_.is_open())
    {
        std::cout << "[ERROR] socket_ is not open\n";
        return;
    }

    std::fill_n(read_buffer_, MAX_MSG, '[=12=]');

    // it works
#if 0
    async_read(socket_, boost::asio::buffer(read_buffer_),
        boost::bind(&connection::on_read_completion, this->shared_from_this(), _1, _2),
        boost::bind(&connection::on_read, this->shared_from_this(), _1, _2));
#else // not works
    async_read(socket_, boost::asio::buffer(read_buffer_),
        [this](const err& error, size_t bytes)->size_t
        {
            if (error) { return 0; }
            bool found = std::find(read_buffer_, read_buffer_ + bytes, '\n') < read_buffer_ + bytes;                return found ? 0 : 1;
        },
        [this](const err& error, size_t bytes)->void
        {
            if (!started_) { return; }
            if (error)
            {
                std::cout << "[ERROR] async_read\n" << error.message();
                return;
            }

            std::string msg(read_buffer_, bytes);
            on_message(msg);
        });
#endif
    }

问题是 lambda [capture] 不包含 shared_ptr 本身。所以当它调用 on_read_completion() 时,lambda 捕获这不是指向我想要的 shared_from_this()。

对此我需要一个明智的建议。请帮助我。

哦,我找到问题所在了。

...
async_read(socket_, boost::asio::buffer(read_buffer_),
  [this](const err& error, size_t bytes)->size_t
  {
    if (error) { return 0; }
    bool found = std::find(read_buffer_, read_buffer_ + bytes, '\n') < read_buffer_ + bytes;
    return found ? 0 : 1;
  },
  [this, self = std::move(this->shared_from_this())](const err& error, size_t bytes)->void
  {
    if (!started_) { return; }
    if (error)
    {
      std::cout << "[ERROR] async_read\n" << error.message() << "\n";
      return;
    }
    std::string msg(read_buffer_, bytes);
    self->on_message(msg);
});

...

成功了!

但是,如果您对此有任何提示,请发表评论!谢谢。

你已经想通了 this 除了共享指针之外还需要显式捕获,后者只是为了生命周期保证。

但是你原来的问题比你知道的更有趣! lambda 和 bind 表达式之间存在细微差别。如果您使用 bind 绑定到通用处理程序,它可能会在 ADL 规则下保留 asio_handler_invoke(或更现代的 get_associated_executor)语义。

这在最终用户层面很少是一个问题,但如果你打算提供一个通用的可组合操作库,你可能会关心这种细节,因为未能保留调用语义可能会导致错误(例如当组合处理程序绑定到链执行器时)。

As a sidenote, in the case you showed, consider using the overload of async_read_until that take a string(view) or regex.