异步回调中的 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.
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.