我正在尝试开发ASIO应用程序并已提及Chat-Server
当我的CServer Object
破坏时,CSerSessionsManager Object
会导致shared pointer
破坏 - 这会将CSerCession Objects
保留到所有活动的聊天会话中。它会导致所有活动的class CServer {
CServer(asio::io_service& io_service, const std::string serIdentity, std::string IP, const std::string port);
~CServer();
.....
private:
mutable tcp::acceptor acceptor_; // only in the listener
asio::io_service& io_;
CSerSessionsManager mng_;
......
};
class CSerSessionsManager{
public:
CSerSessionsManager();
~CSerSessionsManager();
void addSession(sessionPtr session);
void dropSession(sessionPtr session);
private:
std::set<sessionPtr> sessions_; //Active Sessions : Online Info
};
class CSerSession : public std::enable_shared_from_this<CSerSession>{
public:
CSerSession(asio::io_service& io_service, CSerSessionsManager& mng, const std::string serverID,
const std::string ip, const std::string port);
~CSerSession();
.......
private:
mutable tcp::socket socket_; // client connection
CSerSessionsManager& manager_;
......
};
也被破坏。
参见定义
CSerSession Object
但是,由于read error
会导致read_handle()
导致活动会话void CSerSession::handle_read(const asio::error_code& error /*error*/, size_t bytes_transferred /*bytes_transferred*/)
{
if (!error)
{
//do Something
}
else
{
DEBUG_MSG("Read Error Detected : " << error.message());
//Check If shared_from_this() is valid or not
try
{
//if (error == asio::error::operation_aborted)
manager_.dropSession(shared_from_this()); //Exception Here
}
catch (const std::bad_weak_ptr& e)
{
DEBUG_MSG(e.what());
throw e;
}
return;
}
}
,并且会调用this 0x0044697c {socket_={...} manager_={sessions_={ size=??? } sessionPool_={ size=??? } } ip_=<Error reading characters of string.> ...}
std::enable_shared_from_this<channel::CSerSession> {_Wptr={[deleter and allocator]={_Uses=??? _Weaks=??? } } }
socket_ {...}
manager_ {sessions_={ size=??? } sessionPool_={ size=??? } }
ip_ <Error reading characters of string.>
port_ <Error reading characters of string.>
parentServer_ <Error reading characters of string.>
servicedClientID_ <Error reading characters of string.>
serSessioID_ <Error reading characters of string.>
serSessionIdentifier_ <Error reading characters of string.>
privilege_ -274
serSessionIdentitySet_ true (238)
msg_ {received_=0x00446a77 "þîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþî... }
writeQueue_ { size=4277075694 }
。
manager_.dropSession(shared_from_this());
代码在此处异常时抛出异常 在调试时它显示:
std::enable_shared_from_this<channel::CSerSession> {_Wptr={[deleter and allocator]={_Uses=??? _Weaks=??? }
我可以看到调试器显示CSerSession object
时正在调用read_error
。
在设置manager_.dropSession(shared_from_this());
时this object
被破坏后被调用。出错时的默认行为是销毁会话,因此read_error
是强制性的。
问题在于manager_.dropSession(shared_from_this());
导致read error
的破坏导致read_handle()
再次尝试通过manager_.dropSession(shared_from_this());
销毁同一个对象
如何解决错误?
修改 总结问题:
聊天会话期间的任何错误都应设置为CSerSession Object
,并应调用read error
,然后通过manager_.dropSession(shared_from_this());
但是当我的聊天会话shared_from_this()
超出范围,即调用析构函数时,它也会导致{{1}}处于活动状态。所以再次调用{{1}}。
所以基本上{{1}}是从析构函数中间接调用的。
答案 0 :(得分:2)
当您从套接字读取并设置CSerSession::handle_read
读取处理程序时,您应该绑定shared_from_this()
而不是this
。
例如,您的async_read()
应该与此类似:
socket_.async_read(boost::asio::buffer(...),
std::bind(&CSerSession::handle_read, shared_from_this(),
std::placeholder::_1,
std::placeholder::_2);
您观察到的问题是由事件队列的性质引起的。当您销毁CSerSession
事件队列中的某些事件时,可能会将this
指针指向已经被破坏的对象。这就是为什么开发人员建议使用shared_ptr
和shared_from_this()
。当您通过shared_ptr
而不是this
时,您可以保留感兴趣的对象。
回复您的修改:
您说的是从析构函数中间接调用manager_.dropSession(shared_from_this());
。但是,如果read_handle()
仍然引用它,对象如何被破坏呢?如上所述,您是否向read_handle()
提供了shared_from_this()
?