3

I have been working with boost::asio for a while now and while I do understand the concept of the asynchronous calls I am still somewhat befuddled by the memory management implications. In normal synchrous code the object lifetime is clear. But consider a scenario similar to the case of the daytime server:

There might be multiple active connections which have been accepted. Each connection now sends and receives some data from a socket, does some work internally and then decides to close the connection. It is safe to assume that the data related to the connection needs to stay accessible during the processing but the memory can be freed as soon as the connection is closed. But how can I implement the creation/destruction of the data correctly? Assuming that I use classes and bind the callback to member functions, should I create a class using new and call delete this; as soon as the processing is done or is there a better way?

hfhc2
  • 4,182
  • 2
  • 27
  • 56
  • I do not find the given answer to be real world or acceptable, and commented on it as to why. I am asking related question: http://stackoverflow.com/questions/43239208/how-to-design-proper-release-of-a-boostasio-socket-or-wrapper-thereof for any whom google this one up. – Christopher Pisz Apr 05 '17 at 21:25

1 Answers1

1

But how can I implement the creation/destruction of the data correctly?

Use shared_ptr.

Assuming that I use classes and bind the callback to member functions, should I create a class using new and call delete this; as soon as the processing is done or is there a better way?

Make your class inherit from enable_shared_from_this, create instances of your classes using make_shared, and when you bind your callbacks bind them to shared_from_this() instead of this. The destruction of your instances will be done automatically when they have gone out of the last scope where they are needed.

Drax
  • 12,682
  • 7
  • 45
  • 85
  • one note: only `boost::bind` works with `boost::shared_ptr` AFAIK (although you can achieve the same with a lambda that keeps `shared_from_this()` by value) – sehe Jul 02 '14 at 13:01
  • Well, it seems to work with the ordinary `std::bind` as well. Thanks for pointing this out, the change is quite subtle. – hfhc2 Jul 02 '14 at 14:47
  • Another question comes to mind: What happens if I use the `shared_from_this()` function on an object which lies on the stack? Will this cause a segfault when the poiner is destroyed? – hfhc2 Jul 03 '14 at 12:51
  • `shared_from_this()` is intended to get a copy of a `shared_ptr` already owning `this` instance, don't use it if your instance is not owned by a `shared_ptr`, AFAIK the exact behaviour is not really defined. – Drax Jul 03 '14 at 12:54
  • Well, that pretty much means that I have to put everything in the heap though, doesn't it? – hfhc2 Jul 03 '14 at 13:24
  • Pretty much yes. But since your data have to survive asynchronous operations which by nature are spread across different scopes, it make sense for your data's life cycle not to be tied to a particular scope and thus not to be on a particular function's stack but on the "global stack" which is the heap. You could get away without heap allocation but you would have to copy/move around your data, and in case of non-linear flow you could easily fall into the trap of accessing different instances which is avoided by `shared_ptr`. – Drax Jul 03 '14 at 13:44
  • This is not an acceptable solution. What if the server wanted to send "Hi" to all its client connections every 5 minutes. It would not be possible because you are trying to cheat like the boost::asio tutorial by skipping the lifetime management and rely on shared_ptr to stay outstanding on receive calls. This is not real world. If you maintain a collection, the connections never get cleaned up because 1 reference outstanding. A collection is necessary for a real world server. – Christopher Pisz Apr 05 '17 at 21:10
  • Asking related question: http://stackoverflow.com/questions/43239208/how-to-design-proper-release-of-a-boostasio-socket-or-wrapper-thereof – Christopher Pisz Apr 05 '17 at 21:24
  • @ChristopherPisz I don't see how this is incompatible with sending "hi" to all clients connection every 5 min, this is totally and easily doable without any problem. Also your comment seems to imply that you understood "use shared_ptr instead of a connection" which is not what i'm advising, i'm saying "put your connection inside a shared_ptr" which is pretty different. I agree that you need a collection, i'm just saying you should have a collection of shared_ptr. And finally you destroy your connection by removing the shared_ptr from your connection when it is no longer needed. – Drax Apr 06 '17 at 08:30
  • @Drax if you have a collection of shared_ptr then your connections never get destroyed, as long as they are in the collection. Removing shared_ptr from the collection in order to destroy it will introduce the same race conditions that were a problem in the first place. The problem becomes "when to remove the shared_ptr from the collection" rather than "when to destroy the connection." Using weak_ptrs on the otherhand, as suggested in my related question, by other posters, seems viable. – Christopher Pisz Apr 06 '17 at 14:24
  • @ChristopherPisz using weak_ptrs implies you already have shared_ptrs stored somewhere in the first place, so you will still going to need that collection of shared_ptr somewhere in some form and i don't see how "when to remove the shared_ptr" is a problem, in the end you will need a logic as to when your connection ends no matter what form you use for storage – Drax Apr 07 '17 at 12:39