Any data that needs to survive across several callback invocations requires shared ownership. This means that the data must be allocated on the heap and probably also requires reference counting. With lambdas it's also easy to make mistakes, e.g. by capturing variables on the stack by reference.
In a coroutine everything can just live on the stack because the stack frame itself is kept alive across the asynchronous function calls.
Don't you see the big difference regarding lifetime management?
But that's not what you want. The context object should be freed when the associated operation finishes (either successfully or with an error), not when the parent goes out of scope. With coroutines I can simply put the context object on the stack and when the task finishes, the object automatically goes out of scope.
In a coroutine everything can just live on the stack because the stack frame itself is kept alive across the asynchronous function calls.
Don't you see the big difference regarding lifetime management?