C++协程中promise与返回对象的销毁顺序是否有标准规定?
C++协程中promise_type与return_object的销毁顺序问题
问题背景
给定如下C++协程代码:
#include <iostream> #include <coroutine> class eager { public: struct promise_type { promise_type() { std::cout << "promise_type ctor" << std::endl; } ~promise_type() { std::cout << "~promise_type dtor" << std::endl; } struct return_object { return_object() { std::cout << "return_object ctor" << std::endl; } ~return_object() { std::cout << "~return_object dtor" << std::endl; } operator eager() { return {}; } }; auto get_return_object() noexcept { return return_object{}; } constexpr auto initial_suspend() const noexcept { return std::suspend_never{}; } constexpr auto final_suspend() const noexcept { return std::suspend_never{}; } constexpr auto return_void() const noexcept {} auto unhandled_exception() -> void { throw; } }; }; auto coroutine() -> eager { co_return; } auto main() -> int { coroutine(); return 0; }
该协程的initial_suspend和final_suspend都返回suspend_never,意味着协程会同步执行完毕,不会挂起。
不同编译器的输出差异
MSVC/GCC输出顺序:
promise_type ctor return_object ctor ~promise_type dtor ~return_object dtorClang输出顺序:
promise_type ctor return_object ctor ~return_object dtor ~promise_type dtor
原因分析
协程的简化转换代码容易让人误以为promise_type是普通局部变量,会按构造逆序销毁,但实际差异源于编译器对协程状态存储位置的选择:
- Clang实现:将
promise_type作为栈上局部变量,与return_object遵循普通局部变量的销毁规则——按构造顺序的逆序销毁。由于promise_type先构造、return_object后构造,因此return_object先销毁,promise_type后销毁。 - MSVC/GCC实现:将
promise_type存储在堆分配的协程状态中。当协程同步执行完毕(final_suspend不挂起),堆上的协程状态会立即销毁(包含promise_type的销毁);而return_object是栈上临时对象,会在函数返回后、调用点结束时销毁,因此promise_type先销毁,return_object后销毁。
标准规定
C++20标准并未明确规定这种同步执行的协程中,promise_type与无关联的return_object的销毁顺序。标准允许编译器选择协程状态的存储位置(栈或堆),只要符合协程核心语义。因此两种编译器的行为均符合标准要求。
内容的提问来源于stack exchange,提问作者slyx
相关产品推荐
相关产品推荐

