On 17/07/2019 23:03, JH wrote:
Of course, then you can't use destruction of that object to trigger the close in the first place, which can have consequences for the rest of your app. There are some ways around this, such as separating the "real" container of the socket/buffer from the "logical" container from the perspective of the rest of the app.
Did you mean if to use class destructor to trigger the close, it would cause errors like pure virtual method called terminate called without an active exception? Did you allude every close need be explicitly called in functions not the destructors, especially the derived the class?
Calling close() in the destructor of the class that the handlers are defined on is rarely the correct choice. If you're not using shared_ptr, then you've called close() too late -- there is still an outstanding async operation but you're in the process of deleting the object that will be called when that (later) completes, meaning that you have a dangling pointer and will be accessing deleted memory later. If you are using shared_ptr, then the close() in the destructor is (mostly) pointless, because the destructor won't get called until all the pending operations are already ended, which *usually* means that something else has already called close() first. (Although you have to be a little careful of loopholes, such as when your async_read handler doesn't start a new read, either due to error or exception. Still, as long as you're holding the socket by value and you don't have any pending async operations on it, it's safe to just let the socket be destroyed without explicitly close()ing it.) So yes, you should be calling close() from some other method. This might be an explicit disconnection operation, or following a failed read operation, or in the destructor of some other class that is different from the shared_ptr used for the operations themselves. A useful trick is to implement the pimpl idiom using a shared_ptr -- your 'outer' public class can call close() in its destructor because the shared_ptr is to the 'inner' private class instead. Just avoid calling "out" from the inner class to the outer class in handlers, because the inner class will have a longer lifetime than the outer class.
So all the callbacks need be wrapped by shared_ptr? Does that mean the bind callback:
boost::bind(&SocketHandler::Handshake, this, boost::asio::placeholders::error)
Should be replaced by boost::bind(&shared_ptrSocketHandler::Handshake, this, boost::asio::placeholders::error)
No, not even slightly. Have a look at the example code included with Asio.