I finally figured it out, and the short answer is that it was primarily a coding / streaming error on my part. I determined this by creating a simpler example of stand-alone code and found that it does not exhibit the same behavior. I had to do this in the first place, and I'm sorry that I took the time to spend the time. To answer my original questions in full, though:
1 - Are there better methods for removing child objects, which are also signal emitters, from parent slots?
No one answered. I think my suggestion and sample code above, where I use shared_from_this, works fine.
Also, as pointed out by Villintehaspam in the comments above, it would be better to use boost :: signal2, which seems to have better support for controlling the signal's lifetime.
2 - Any ideas as to why io_service hangs when I delete my network client object
My mistake was that the destructor in my NetworkClient ran an operation that called the current thread (and only the thread available to handle asych IO operations) to block indefinitely. I did not understand that this was happening. New clients could still connect due to the way I handle the acceptor in its own thread, regardless of the asynch io_service operations. Of course, although I planned asynchronous operations for a new client, they never started because the one thread that I made available to io_service was still blocked.
Thanks to everyone who took the time to look at this.
source share