On 10/09/2019 17:10, Stephan Menzel wrote:
I'm in the process of creating more such composed ops for ever recurring use cases and perhaps I find a way to tie this lambdas lifetime to the whole operation. As it happens, my gut felling tells me there are cases when the timer lambda will dangle around and potentially crash, perhaps when the op is used and the io_service being destroyed and not polled before destruction. I couldn't verify this in the unit test yet but there's often cases like this that go overlooked.
Yes, you may have a lifetime problem if the timer has not yet expired when m_socket is destroyed. Since the owner of the timer also assumes a shorter lifetime than m_socket (due to capturing it by reference), the timer should get cancelled before m_socket is destroyed (unless you have a different bug). The handler might not have been called yet, but on the cancellation path you immediately return anyway, so it shouldn't be an issue. (Though there might be a corner case if it expires just as you destroy things.) If you do dispose of the io_service before all handlers are called, then they will not be called, but their destructors will still fire. Occasionally this means you need to be careful about the order of destruction when the destructors aren't trivial, but otherwise this behaves sensibly. But yes, async can make it quite hairy to verify that lifetimes occur the right way around -- which is one of the reasons why you see shared_ptr used a lot in async code. When you're trying to provoke these sorts of issues in unit tests, using run_one() can be very helpful.