繁体   English   中英

promise 的销毁命令并为 C++ 协程返回 object

[英]destruction order of promise and return object for C++ coroutine

#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;
}

您可以在此处查看 MSVC、clang 和 GCC 的结果: https://godbolt.org/z/Yan9s9TPE

根据很多关于协程的文章, coroutine()将被转换成...

auto coroutine() -> eager {
    eager::promise_type promise;
    auto res = promise.get_return_object();
    // initial suspend
    promise.return_void();
    // final suspend
    return res;
}

一眼看去,由于promise object是先构建的,我还以为是最后一个object被析构。

但是,MSVC 和 GCC 显示相反的顺序:

// from MSVC/GCC
promise_type ctor
return_object ctor
~promise_type dtor
~return_object dtor

另一方面,clang 显示了我的预期:

// from clang
promise_type ctor
return_object ctor
~return_object dtor
~promise_type dtor

哪一个是对的? 或者,promise object 的销毁顺序和返回 object 是否只是标准未指定?

根据很多关于协程的文章

那么“很多关于协程的文章[原文如此]”是不正确的。

结果 object 不在协程栈上。 不能在协程堆栈上,因为它是协程初始调用的结果 object

C++ 标准对get_result_object的描述是这样的

表达式promise.get_return_object()用于初始化协程调用的右值结果或右值结果 object。 对 get_return_object 的调用在对initial_suspend的调用之前排序,并且最多调用一次。

它发生在initial_suspend之前并且被调用一次。 这就是它要说的全部。 因此,函数的结果对象的其他一切都正常工作; 在这种情况下,它只是在 function 正确启动之前初始化,而不是在 function 即将返回时初始化。

按照 C++ 的一般规则,函数的结果 object 在调用者的堆栈上,而不是被调用的 function 的堆栈上。 因此,当评估promise.get_result_object()时,它正在初始化调用者提供的存储。

main丢弃表达式coroutine()的结果。 这意味着它将根据 prvalue 结果 object 显示一个临时文件,并且此临时文件的类型将为eager 临时文件将被销毁,但只有控制权返回main之后。

这是棘手的部分: get_result_object()的返回纯右值并不eager 它是eager::promise::result_object 初始化返回值需要执行从result_objecteager的隐式转换。 这需要显示一个result_object类型的临时对象来执行该转换。

销毁临时工的标准规则是

临时对象作为评估完整表达式 ([intro.execution]) 的最后一步被销毁,该表达式(在词法上)包含它们的创建点。

但是……这里的“完整表达”是什么?

人们会假设它是promise.get_result_object()表达式。 但这是 C++ 规则的“完整表达式”吗? 这些规则相当深奥和技术性 有人可能会争辩说promise.get_result_object()被用来初始化一个 object,因此它实际上是一个“init-declarator”。 但是“init-declarator”是一段语法, promise.get_result_object()并没有被文本声明为“init-declarator”。

可以说唯一肯定是完整表达式的表达式是coroutine() 因此,可以提出这样的论点,即任何用于初始化返回值 object 的临时对象都应该持续存在,直到控制权返回给调用者。

我认为标准措辞未明确规定,因此在提供澄清之前,这两个版本同样合法。 Clang 的版本更有意义(但不是出于您声称的原因),但其他版本至少是有争议的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM