代码之家  ›  专栏  ›  技术社区  ›  doraemon

c++协程中局部变量的生存期

  •  0
  • doraemon  · 技术社区  · 3 年前

    对于c++20协程,我试图了解是否需要在堆中分配协程中的局部变量。我有一个 runnable code in godbolt ,以预期输出运行。下面列出了部分代码供我们讨论。

    generator<int> my_coroutine()
    {
    
      // Does vec needs to allocated in heap?
      // auto vec = std::make_shared<std::vector<int>>(std::initializer_list<int>{ 1, 2, 3, 4, 5 });
      auto vec = std::vector<int>{ 1, 2, 3, 4, 5 };
      for (auto&& i : vec)
      {
        co_yield i;
      }
    }
    
    int main()
    {
      for (auto i : my_coroutine())
      {
        std::cout << i << " ";
      }
      std::cout << std::endl;
      return 0;
    }
    

    我的问题

    1. 是矢量的寿命跨度为当前的悬挂点。“跨越当前暂停点”的真正含义是什么
    2. 我应该使用在堆中分配vec吗 std::make_shared ?
    3. 从…起 cppreference ,我在中看到以下内容 处决 部分这是否意味着协同状态将复制 vec 堆里?(不管是否 vec vector<int> shared_ptr<vector<int>> )

    协程状态,它是一个内部堆分配的(除非优化了分配)对象,包含

    1. promise对象
    2. 参数(全部按值复制)
    3. 当前挂起点的一些表示,这样简历知道在哪里继续,销毁知道范围内的局部变量
    4. 局部变量和临时变量,它们的寿命跨越当前暂停点。
    1 回复  |  直到 3 年前
        1
  •  1
  •   Nicol Bolas    3 年前

    等待式协同程序(在几乎所有提供它们的语言中)的全部意义在于,代码看起来像同步代码,同时能够在某种程度上异步执行。这个 await -等效表达式不会从根本上改变它们周围代码的性质,您可以对代码进行推理,就好像一切都按顺序进行一样。对于C++协同程序,这包括自动变量。

    如果你在当地 vector<int> ,该变量以相同的方式工作,无论它是否为协程。如果您有此声明: vector<int> vec = ...; ,您可以使用名称 vec 在声明之后的任何指针处引用该对象,但在离开声明所在的范围之前。

    无论是否存在 co_await 是否在这些点之间。这就是“寿命跨越当前悬挂点”的意思:访问一个变量,该变量的寿命在某个悬挂点之前开始,在该悬挂点之后的某个地方。

    简单地说,如果您跨挂接点访问本地声明的对象,则需要将该对象保留在某个位置,以便在挂起和恢复协程之后它仍然存在。维基正在解释它是如何工作的。