Safe deletion of caller object in callback function

The code segment from the library:

class Client{ public: class CallBack { public: virtual void onData(Client* caller, std::string& data) =0; }; Client(CallBack* callback):m_callBack(callback){} virtual ~Client(){} void onData(std::string data) { m_callBack->onData(this, data); m_totalDataVol += data.size(); } private: CallBack* m_callBack; int m_totalDataVol = 0; } 

Segment of code from the application:

 class AppHandler: public Client::Callback { void onData(Client* caller, std::string& data) { /* Some complex logic and check certain conditions*/ delete caller; // Application will crash, due to // accessing member of deleted object (m_totalDataVol) } } 

In addition, the Caller object (an instance of the Client class) belongs to the application, and the application has no restrictions for its removal.

How do I solve this problem?

A very complex scenario: the Client class of the base library can be extended by another library ( ClientEx class), and the application can use this extended library (not the base library)

+6
source share
1 answer

Return a bool callback to indicate whether the calling user should delete itself. Do not remove the client from the callback.

Also, do I need to call a callback at all if data.size == 0 ? Client can check this condition before calling the callback and delete it (or otherwise handle it accordingly).

If the call still needs to be called, perhaps you can avoid changing the return type by simply checking the condition on the client after the call:

 void onData(std::string data) { m_callBack->onData(this, data); if (data.size() != 0) { m_totalDataVol += data.size(); } else { delete this; } } 

Alternatively, if you really have to allow the callback to delete the client, you will need some way of tracking when the client was deleted, which you can use in the client itself. This means maintaining a link to another object:

 class Client{ public: class CallBack { public: virtual void onData(Client* caller, std::string& data) =0; }; Client(CallBack* callback):m_callBack(callback){}, was_deleted(nullptr) virtual ~Client(){ if (was_deleted) *was_deleted = true; } void onData(std::string data) { bool *was_deleted = new bool(); this->was_deleted = was_deleted; m_callBack->onData(this, data); if (! *was_deleted) { m_totalDataVol += data.size(); this->was_deleted = nullptr; } delete was_deleted; } private: CallBack* m_callBack; int m_totalDataVol = 0; // When issuing a callback, holds a pointer to a flag that can // be used to track if this object has been deleted: bool * was_deleted; } 

(Please note that the above solution is not thread safe, but it can probably be done like that. Also note that the code above does not compile, since the example code in your question does not work - I tried to match the original code, and it is also possible the principle should be applicable to the real code).

+2
source

All Articles