asio icon indicating copy to clipboard operation
asio copied to clipboard

co_composed prematurely releases objects captured by the implementation lambda before the first co_await

Open lnpg opened this issue 1 year ago • 2 comments

struct Func {
    int value = 1;

    Func() {
        std::cout << "Func() " << std::uintptr_t(this) << "\n";
    }

    Func(Func &&) {
        std::cout << "Func(Func&&)  " << std::uintptr_t(this) << "\n";
    }

    ~Func() {
        value = 0;
        std::cout << "~Func() " << std::uintptr_t(this) << "\n";
    }
};

template<asio::completion_token_for<void(asio::error_code)> Token>
auto asyncCoCompose(asio::io_context &ioCtx, Token &&token) {
    return asio::async_initiate<Token, void(asio::error_code)>(
        asio::experimental::co_composed<void(asio::error_code)>(
            [fun=Func{}](auto state, asio::io_context &ioCtx)-> void {
                asio::steady_timer timer{ioCtx};
                timer.expires_after(std::chrono::seconds{1});
                std::cout << "Before co_await " << std::uintptr_t(&fun) << " " << fun.value << "\n";
                co_await timer.async_wait(asio::deferred);
                std::cout << "After co_await " << std::uintptr_t(&fun) << " " << fun.value << "\n";
                co_return {};
            }
            , ioCtx)
        , token, std::ref(ioCtx));
}

int main() {
    asio::io_context ioCtx{};
    asyncCoCompose(ioCtx, [](asio::error_code ec) {
        std::cout << "finish\n";
    });

    ioCtx.run();

    return 0;
}

the lambda for implementation parameter of co_composed captures a Func object fun, which get destructed before co_await timer.async_wait(asio::deferred);

lnpg avatar Jun 15 '24 12:06 lnpg

Your lambda is getting destructed when async_wait returns after the coroutine is suspended. All capture variables will be destructed. Work around this by saving off your captured variables to the stack before this happens, or pass the objects you need to keep around as lambda invocation parameters. See Daniel Chen's article on this gotcha.

mscottmueller avatar Jul 07 '24 16:07 mscottmueller

co_spawn seems to have done the copy by itself, I thought co_composed should be the same

lnpg avatar Jul 10 '24 10:07 lnpg