首页 > 解决方案 > gcc 10 在 co_await 表达式完成之前销毁传递给返回等待器类型的函数的临时参数

问题描述

我在 windows 10 上的 wsl 1 上使用 gcc 10 和协程,并注意到传递给返回等待程序的函数的参数在协程挂起时被销毁

clang 和 msvc 不这样做,而是保留临时变量,直到表达式完成

演示问题的代码:

#include <cstdio>
#include <thread>
#if defined __clang__ || defined _WIN32
#include <experimental/coroutine>
using coro_handle = std::experimental::coroutine_handle<>;
using suspend_never = std::experimental::suspend_never;
#else
#include <coroutine>
using coro_handle = std::coroutine_handle<>;
using suspend_never = std::suspend_never;
#endif // __clang__


struct arg_t
{
    arg_t() { printf("arg_t()\n"); }

    ~arg_t()
    {
        printf("~arg_t()\n");
    }
};

struct awaiter_t
{
    awaiter_t() { printf("awaiter_t()\n"); }

    ~awaiter_t()
    {
        printf("~awaiter_t()\n");
    }

    bool await_ready() const noexcept 
    {
        printf("await_ready()\n");
        return false;
    }

    void await_suspend(coro_handle coro)
    {
        printf("await_suspend()\n");
        std::thread([coro]() mutable { std::this_thread::sleep_for(std::chrono::seconds(3)); coro.resume(); }).detach();
    }

    void await_resume()
    {
        printf("await_resume()\n");
    }
};

struct task_t
{
    struct promise_type
    {

        task_t get_return_object() { return {}; }

        suspend_never initial_suspend() noexcept { return {}; }

        suspend_never final_suspend() noexcept { return {}; }

        void unhandled_exception() noexcept { std::terminate(); }

        void return_void() {}

    };

    task_t() = default;

};

awaiter_t make_awaiter(const arg_t& arg)
{
    return awaiter_t{};
}


task_t test_awaiter()
{
    co_await make_awaiter(arg_t{});
}

int main()
{
    test_awaiter();
    std::this_thread::sleep_for(std::chrono::seconds(4));
    return 0;
}

gcc 测试:https ://godbolt.org/z/cT4q8d

使用 gcc 标志编译:-std=c++20 -Wall -pthread -fcoroutines

输出:

arg_t()
awaiter_t()
~arg_t() -> destroyed before await_ready !
await_ready()
await_suspend()
await_resume()
~awaiter_t()

铿锵测试:https ://godbolt.org/z/fcrzPM

用clang标志编译:-std=c++20 -Wall -pthread -stdlib=libc++

输出:

arg_t()
awaiter_t()
await_ready()
await_suspend()
await_resume()
~awaiter_t()
~arg_t() -> destroyed after the awaiter is destroyed

msvc 的行为也像我在这里尝试的 clang:Do temporaries 传递给返回 awaitable 的函数在使用 co_await 的挂起点后仍然有效

它是 gcc 中的错误吗?还是编译器可以在这里随意做任何事情?

标签: c++g++clang++c++20c++-coroutine

解决方案


推荐阅读