13965

shared_from_this() is called after object pointing by this is destroyed: C++ ASIO

Question:

I am tryin to develop ASIO Application and have referred <a href="http://think-async.com/Asio/asio-1.10.2/src/examples/cpp03/chat/chat_server.cpp" rel="nofollow">Chat-Server</a>

When my CServer Object destructs it causes CSerSessionsManager Object to destruct- which holds shared pointer to all active chat sessions. It causes all active CSerCession Objects to destroy as well.

See the Definitions

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_; ...... };

But since the CSerSession Object destroys it causes read error for active session and read_handle() is called.

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; } }

The code throws exception at <strong>Exception Here.</strong> On debugging it shows:

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 }

I can see that manager_.dropSession(shared_from_this()); is being called when debugger shows std::enable_shared_from_this<channel::CSerSession> {_Wptr={[deleter and allocator]={_Uses=??? _Weaks=??? }.

It is being called after the destruction of CSerSession object as read_error is being set. Default behavior on error is to destroy the session and hence manager_.dropSession(shared_from_this()); is mandatory there.

The problem is that the destruction of this object causing read_error which again tries to destroy the same object via manager_.dropSession(shared_from_this());

How do I resolve the error?

<strong>EDIT:</strong> Summarizing the Issue:

Any error during chat session should set read error and read_handle() should be called which then destroys chat session via manager_.dropSession(shared_from_this());

But when my chat session CSerSession Object is going out of scope i.e. destructor is called, it is also causing read error as it was active. So again manager_.dropSession(shared_from_this()); is being called.

So basically shared_from_this() is being indirectly called from destructor.

Answer1:

When you read from socket and set CSerSession::handle_read read handler, you should bind shared_from_this() instead of this.

For example, your async_read() should look similar to this:

socket_.async_read(boost::asio::buffer(...), std::bind(&CSerSession::handle_read, shared_from_this(), std::placeholder::_1, std::placeholder::_2);

The problem you observe is caused by the nature of event queue. When you destroy CSerSession some events in the event queue may keep this pointer to object that was already destructed. Thats why developers recommend using shared_ptr and shared_from_this(). When you pass shared_ptr instead of this you keep object of interest alive.

<strong>Response to your edit:</strong>

You are saying that manager_.dropSession(shared_from_this()); is being indirectly invoked from destructor. But how come object is being destructed, if read_handle() still keeps a reference it? Do you provide read_handle() with a shared_from_this() as I mentioned above?

Recommend

  • Converting code using hash to array
  • PHP PDO Connection to Azure SQL - Invalid Object Name [table]
  • Jackson JSON Not Formatting Correctly
  • How do I check if a SSLSocket connection is sane on Java?
  • boost asio - connect using an ip address
  • How to send data between .NET 4.5 and .NET 4.0 with Sockets?
  • PHPCrawl fails to create SSL socket
  • java socket timeout behaviour
  • Zookeeper -Kafka: ConnectException - Connection refused
  • mysql_* to MySQLi
  • starttls on node.js > 0.4.0
  • “Permission denied” while connecting to a page, even with INTERNET permission
  • Reconnection in socket.io problem in `socket.on('message',function(){})`
  • inter thread comunication using ZeroMQ messages [closed]
  • synology php ftp_ssl_connect - Call to undefined function
  • Issue with session.handler.native_file session handler in symfony2
  • How to send an std::vector of unsigned char over an UDP socket using boost asio?
  • PHP Post & Redirect with cURL Same As HTML Form [closed]
  • IP and domain create different session
  • How to read data from socket connection - android
  • Cannot send user message with Spring Websocket
  • Get or convert Week of year to ISO week
  • How to distribute Java-based software?
  • jQuery and Uploadify session in the php file
  • Google OAuth2 for an web application hosted behind NAT (intranet server without public IP)
  • How to resolve docker host names (/etc/hosts) in containers
  • Should I be afraid to use UDP to make a client/server broadcast talk?
  • Error in making a socket connection
  • sweetalert2 inputoptions from file in select example
  • New Firebase failed: First argument must be a valid firebase URL and the path can't contain “.”
  • JSON encode and decode on PHP
  • Building Qt project for C++11 standard
  • Possible to “watch” both HAML and SASS at the same time?
  • Visual Studio 2010 debugger build correctly - compiler pdb and linker pdb not in synch?
  • PHP buffered output depending on server setting?
  • Custom Tabgroup Appcelerator
  • Cannot resolve symbol 'MyApi'
  • How to rebase a series of branches?
  • Where to put my custom functions in Wordpress?
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)