首页 > 解决方案 > 为什么coroutine_handle的操作符bool销毁后返回true?

问题描述

我是 C++20 协程的新手,很惊讶知道销毁后会coroutine_handle::operator bool返回?true

示例程序:

#include <coroutine>
#include <iostream>

struct ReturnObject {
  struct promise_type {
    void return_void() {}
    ReturnObject get_return_object() { return {}; }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void unhandled_exception() {}
  };
};

struct Awaiter {
  std::coroutine_handle<> *hp_;
  constexpr bool await_ready() const noexcept { return false; }
  void await_suspend(std::coroutine_handle<> h) { *hp_ = h; }
  constexpr void await_resume() const noexcept {}
};

ReturnObject
counter(std::coroutine_handle<> *continuation_out)
{
  Awaiter a{continuation_out};
  for (;;)
    co_await a;
}

int main()
{
  std::coroutine_handle<> h;
  std::cout << "before construction " << (bool)h << '\n';
  counter(&h);
  std::cout << "after construction " << (bool)h << '\n';
  h.destroy();
  std::cout << "after destruction " << (bool)h << '\n';
}

https://gcc.godbolt.org/z/a7ehjzhab

它打印

before construction 0
after construction 1
after destruction 1

为什么true破坏后它仍然返回?所以就不能区分活跃coroutine_handle的和被破坏的吗?

标签: c++c++-coroutine

解决方案


因为协程句柄基本上只是保存一个地址。您几乎可以将其视为“协程视图”,它不拥有协程。destroy如果协程无法通过标准控制流(例如生成器)正常退出,则存在。operator boolfor astd::coroutine_handle被定义为等价于return (bool)address();除非它来自 noop 承诺(在这种情况下它只是true)。

因此,当您调用时.destroy(),没有要求(我可以找到)句柄将自身设置为在调用(甚至检查)nullptr之后对句柄进行任何操作(甚至检查),我可以告诉未定义的行为。destroyoperator bool

所以不可能区分活动的 coroutine_handle 和被破坏的 coroutine_handle 吗?

并不真地?你不是故意的。一旦destroy被调用,您应该摆脱句柄或重新初始化它(使用nullptr协程或协程)。


推荐阅读