I think this could be reordered and you would not really need a list: Call `set_reply_data_size` first, and pass the pointer to cancel_async, which would allocate the wait handles if necessary and fill the array directly.
Indeed, nice catch! I didn't have the "counting" pass initially so I actually needed the list at that point, but not so much now. Updated locally.
Another option for wait handle allocation is to move it to async creation unconditionally, which would be better for allocation failure handling, but that might be a waste of handles, so idk.
Right, I thought it might be overkill in the most likely case where CancelIo() is never called.