You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++协程中co_return与掉出末尾的行为差异:标准与Clang实现疑问

协程末尾与co_return的行为差异分析

核心结论

cppreference的表述确实比C++标准更强,Clang 18.1.0的行为完全符合标准,并非bug。

标准与cppreference的表述差异

cppreference的简化描述:

掉出协程末尾等效于co_return;,但如果Promise作用域内找不到return_void声明,行为未定义。

但C标准(C20及后续版本)对两者的执行顺序有明确区分:

  • 当协程正常掉出末尾时:先销毁所有局部变量,再调用promise的return_void()(若该成员存在)。
  • 当执行co_return;时:先调用promise的return_void(),再销毁所有局部变量。

cppreference的“等效”表述忽略了析构顺序的差异,属于过度简化的强表述,标准并未规定两者在析构与return_void的调用顺序上完全一致。

Clang行为的合规性

Clang的实现严格遵循标准:

  • 对于掉出协程末尾的foo()函数,先执行局部变量logger的析构,再调用return_void()。
  • 对于使用co_return;的bar()函数,先调用return_void(),再执行局部变量的析构。

这种行为完全符合标准对两种场景的执行顺序规定,不存在bug。

示例代码

#include <iostream>
#include <coroutine>

struct Coroutine {
    struct promise_type {
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }

        Coroutine get_return_object() { return {}; }

        void unhandled_exception(){}
        void return_void() {
            std::cout << "return_void called\n";
        }
    };
};

struct LogOnDestruct {
    ~LogOnDestruct() {
        std::cout << "Destructed\n";
    }
};

Coroutine foo() {
    LogOnDestruct logger{};
    co_await std::suspend_never{};
}
Coroutine bar() {
    LogOnDestruct logger{};
    co_return;
}

int main() {
    foo();
    bar();

    return 0;
}

运行输出(Clang 18.1.0)

Destructed
return_void called
return_void called
Destructed

内容的提问来源于stack exchange,提问作者Wutz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:51:19