协程参数的生命周期是多少

2023-12-27

#include <iostream>
#include <experimental/coroutine>
#include <string>
#include <thread>
struct InitialSuspend{
    bool await_ready(){
        return false;
    }
    bool await_suspend(std::experimental::coroutine_handle<> h){
          return false;
    }
    void await_resume(){
        
    }
};
struct FinalSuspend{
    bool await_ready() noexcept{
        return false;
    }
    void await_suspend(std::experimental::coroutine_handle<> h) noexcept{
       std::cout<<"FinalSuspend await_suspend\n";
    }
    std::string await_resume() noexcept{
        std::cout<< "await_resume for FinalSuspend\n";
       return "await_resume for FinalSuspend\n";
    }
};
struct Task{
    struct promise_type;
    using coroutine_type = std::experimental::coroutine_handle<promise_type>;
    struct promise_type{
        auto initial_suspend(){
           return InitialSuspend{};
        }
        void unhandled_exception(){
            std::cout<<"unhandled_exception\n";
            std::terminate();
        }
        auto final_suspend() noexcept{
           return FinalSuspend{};
        }
        // void return_value(std::string const& v){
        //    value_ = v;
        // }
        void return_void(){

        }
        auto get_return_object(){
            return Task{coroutine_type::from_promise(*this)};
        }
        std::string value_;
    };
    coroutine_type handler_;
};
struct AwaitAble{
    bool await_ready(){
        return false;
    }
    void await_suspend(std::experimental::coroutine_handle<> h){
        std::cout<<"await_suspend\n";
    }
    std::string await_resume(){
       std::cout<<"await_resume\n";
       return "abc";
    }
};
struct Observe0{
    Observe0(int v):id_(v){
        std::cout<< id_ <<"  constructor0\n";
    }
    ~Observe0(){
        std::cout<< id_ <<" destroy0\n";
    }
    Observe0(Observe0 const& v):id_(v.id_+1){
        std::cout<< id_<<" copy constructor0\n";
    }
    Observe0(Observe0&& v):id_(v.id_+1){
       std::cout<< id_<<" move constructor0\n";
    }
    int id_;
};
Task MyCoroutine(Observe0 p){
    auto r1 = co_await AwaitAble{};
}
int main(){
    Observe0  aa{1};  //#1
    auto r = MyCoroutine(aa); //#2
    std::cout<<"caller\n";
    r.handler_.resume();
    r.handler_.destroy();
    std::cin.get();
}

The output https://godbolt.org/z/c8Wqejxox is:

1  constructor0
2 copy constructor0
3 move constructor0
await_suspend
2 destroy0
caller
await_resume
FinalSuspend await_suspend
3 destroy0
1 destroy0

我们可以通过上面的代码来观察对象的创建或销毁。第一次打印发生在#1,构造对象a。第二次打印发生在协程参数初始化时#2。第三次打印发生在协程参数副本初始化时,由以下规则决定:
[dcl.fct.def.协程#13] https://eel.is/c++draft/dcl.fct.def.coroutine#13

当调用协程时,在初始化其参数([expr.call])后,将为每个协程参数创建一个副本。对于 cv T 类型的参数,副本是具有自动存储持续时间的 cv T 类型的变量,该变量是从引用该参数的 T 类型的 xvalue 直接初始化的。

这三个对象都有唯一的编号,方便观察关联对象的生命周期。根据第五次打印,析构函数被调用协程参数谁的名字是p。然而,根据[expr.await#5.1] https://eel.is/c++draft/expr.await#5.1

否则,控制流返回到当前协程调用者或恢复者([dcl.fct.def.coroutine])不退出任何范围([stmt.jump])。

这意味着挂起协程并将控制权转移给调用者,协程的参数范围不被视为退出。因此,参数的生命周期不应结束。为什么参数的析构函数在第一次传递给协程的调用者之后才被调用?它应该被视为编译器中的错误吗?


参数的生命周期不属于函数的作用域;它是的一部分caller's scope https://timsong-cpp.github.io/cppwp/n4861/expr.call#7:

每个参数的初始化和销毁​​都发生在调用函数的上下文中。

这就是 [dcl.fct.def.coroutine#13] 存在的全部原因。为了让协程保留其参数,它必须拥有它们。这意味着must将它们从参数复制/移动到本地自动存储中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

协程参数的生命周期是多少 的相关文章

  • 为什么这个 Web api 控制器不并发?

    我有一个 Web API 控制器 里面有以下方法 public string Tester Thread Sleep 2000 return OK 当我调用它 10 次 使用 Fiddler 时 我预计所有 10 次调用都会在大约 2 秒后
  • 将类对象放置在向量中?

    我注意到我可以将一个类放置在一个向量中 这是我的程序 我收到以下错误 out blackjack exe blackjack obj blackjack obj error LNK2019 unresolved external symbo
  • 从复选框列表中选择循环生成的复选框中的一个复选框

    抱歉我的英语不好 在我的 ASP NET 网站上 我从 SQL 表导入软件列表 看起来像这样 但实际上要长得多 Microsoft Application Error Reporting br br Microsoft Applicatio
  • 当事件button.click发生时,如何获取按钮名称/标签?

    我以编程方式制作按钮并将它们添加到堆栈面板中 以便每次用户导航到页面时按钮都会发生变化 我正在尝试做这样的事情 当我单击创建的按钮时 它将获取按钮的标签并转到正确的页面 但是 我无法使用 RoutedEventHandler 访问按钮元素
  • 如何将 SOLID 原则应用到现有项目中

    我对这个问题的主观性表示歉意 但我有点卡住了 我希望之前处理过这个问题的人能够提供一些指导和建议 我有 现在已经成为 一个用 C 2 0 编写的非常大的 RESTful API 项目 并且我的一些类已经变得巨大 我的主要 API 类就是一个
  • java中如何重新初始化int数组

    class PassingRefByVal static void Change int pArray pArray 0 888 This change affects the original element pArray new int
  • 强制初始化模板类的静态数据成员

    关于模板类的静态数据成员未初始化存在一些问题 不幸的是 这些都没有能够帮助我解决我的具体问题的答案 我有一个模板类 它有一个静态数据成员 必须为特定类型显式实例化 即必须专门化 如果不是这种情况 使用不同的模板函数应该会导致链接器错误 这是
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • 将 Word 转换为 PDF - 禁用“保存”对话框

    我有一个用 C 编写的 Word 到 PDF 转换器 除了一件事之外 它工作得很好 有时 在某些 Word 文件上 后台会出现一条消息保存源文件中的更改 gt 是 否 取消 但我没有对源文件进行任何更改 我只想从 Word 文件创建 PDF
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • C++:二叉树所有节点值的总和

    我正在准备面试 我被一个二叉树问题困住了 我们如何计算二叉树所有节点中存在的值的总和 优雅的递归解决方案 伪代码 def sum node if node NULL return 0 return node gt value sum nod
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • 如何在 sql azure 上运行 aspnet_regsql? [复制]

    这个问题在这里已经有答案了 可能的重复 将 ASP NET 成员资格数据库迁移到 SQL Azure https stackoverflow com questions 10140774 migrating asp net membersh
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点
  • 我可以使用 lambda 函数或 std::function 对象来代替函数指针吗?

    我有一个需要使用的库 它定义了以下内容 typedef void CallbackFunction const int i 并且有一个注册回调的函数 如下所示 void registerCallback CallbackFunction p
  • MySqlConnectionStringBuilder - 使用证书连接

    我正在尝试连接到 Google Cloud Sql 这是一个 MySql 解决方案 我能够使用 MySql Workbench 进行连接 我如何使用 C 连接MySqlConnectionStringBuilder 我找不到提供这三个证书的

随机推荐