我有一个类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就可以判断对象是否已经被破坏了。这是一个肮脏的黑客,但它现在有效。从长远来看,我想有一个更优雅的解决方案。
答案 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;
};