在被指向的对象被销毁之后调用shared_from_this():C ++ ASIO

时间:2015-02-16 14:55:37

标签: c++ c++11 boost-asio smart-pointers

我正在尝试开发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}}是从析构函数中间接调用的。

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_ptrshared_from_this()。当您通过shared_ptr而不是this时,您可以保留感兴趣的对象。

回复您的修改:

您说的是从析构函数中间接调用manager_.dropSession(shared_from_this());。但是,如果read_handle()仍然引用它,对象如何被破坏呢?如上所述,您是否向read_handle()提供了shared_from_this()