C++中的co_return是什么?(如何在协程中返回最终结果)

6次阅读

co_return是协程专用返回语句,需配合promise_type使用,触发return_void()/return_value()并进入final_suspend状态,而非直接返回调用方。

C++中的co_return是什么?(如何在协程中返回最终结果)

co_return 是协程的返回语句,不是普通函数 return 的替代品

它只在标记为 coroutine 的函数(即含 co_awaitco_yieldco_return 的函数)中合法,且必须配合自定义的协程桩(promise_type)才能工作。编译器看到 co_return 会生成对 promise.return_void()promise.return_value(...) 的调用,而不是直接结束函数。

常见错误现象:Error: 'co_return' cannot be used in a function that is not a coroutine——说明函数没被识别为协程,通常因为没用到其他协程关键字,或编译器未启用 c++20 协程支持(如没加 -std=c++20-fcoroutines)。

  • 使用场景:异步 I/O 完成后返回结果(如 Task<int></int>)、生成器末尾收尾(Generator<void></void>)、资源清理后退出协程
  • 若协程返回类型是 void(如 Task<void></void>),必须调用 promise.return_void();若返回非 void(如 int),则调用 promise.return_value(val)
  • 不写 co_return 也不报错,但协程会在函数末尾隐式调用 return_void();显式写更清晰,尤其需要提前退出时

co_return 后协程不立即销毁,而是进入 final_suspend 状态

这是最容易被忽略的一环:co_return 执行完,协程帧(coroutine frame)不会自动释放,而是先挂起在 promise.final_suspend() 返回的 awaiter 上。是否继续执行、何时销毁,全由这个 awaiter 决定。

典型陷阱:忘了重载 final_suspend,或返回了 std::suspend_always{} 却没手动 destroy(),导致协程泄漏、内存不释放。

立即学习C++免费学习笔记(深入)”;

  • 如果希望协程结束后立刻销毁(最常见需求),final_suspend() 应返回 std::suspend_never{}
  • 如果要移交控制权(比如把协程句柄交给 Event loop 处理),可返回 std::suspend_always{},并在外部调用 handle.destroy()
  • 返回 std::suspend_always{} 时,handle.done() 会返回 true,但 handle.destroy() 必须由用户显式调用,否则协程帧永远驻留

co_return 表达式的类型必须能被 promise_type 接受

co_return expr; 中的 expr 类型,必须和 promise_type::return_value(T&&) 的参数类型匹配(或能隐式转换)。否则编译失败,错误信息往往指向 promise 类型里缺失该函数。

例如:声明 Task<:String></:string> 却在协程里写 co_return 42;,就会触发类似 no matching member function for call to 'return_value' 的错误。

  • 基本类型(intstd::string)通常走 return_value(T&&)
  • void 协程只能用 co_return;(无表达式),触发 return_void()
  • 如果想支持多种返回方式(如允许 co_returnco_return std::move(x)),需同时提供 return_value(const T&)return_value(T&&)
  • 注意移动语义:co_return local_obj; 默认触发移动(如果 T 可移动),但若 return_value 参数是 const T&,就只能拷贝

别把 co_return 当 return 用——它不传递值给调用方

co_return 的值不是“返回给调用者”,而是传给协程的 promise,再由 promise 决定如何暴露(比如存入 Task 对象内部、触发回调、填充 future)。调用协程函数得到的只是句柄(std::coroutine_handle)或包装对象(如 Task<int></int>),真正取结果得靠后续机制(如 co_awaitget())。

新手常误以为 auto x = my_coro(); co_return 123; 会让 x 直接等于 123,其实 x 是个待调度的协程对象,里面还没运行,更没结果。

  • 同步获取结果?不行——协程默认惰性求值,必须驱动它(如 co_await xx.get(),后者通常阻塞等待)
  • 想让 co_return val 最终变成调用方拿到的 val,必须确保 promise 正确存储 val,且 awaiter 的 await_resume() 返回它
  • 性能影响:每次 co_return 都涉及一次 promise.return_value() 调用 + 可能的移动/拷贝;避免在热路径频繁返回大对象

协程的返回逻辑绕在 promise 里,不是语法糖,也不是控制流终点。漏掉 final_suspend 或写错 return_value 签名,编译期可能不报错,但运行时行为完全不可控。

text=ZqhQzanResources