我正在追踪 gcc 中的一个错误,并遇到了一种我不知道可接受的行为是什么的情况。假设我们在协程中的某处有一行,例如:
Pair{.x{}, .y=(co_await std::suspend_always{}, 1)};
Run Code Online (Sandbox Code Playgroud)
其中Pair是一些可以使用成员.x(X具有默认构造函数的类型)和(具有 int 构造函数的.y类型)进行聚合初始化的结构。Y这些类型可能都有重要的析构函数。这段代码可以做什么?
C++20 标准第 9.4.1/6 节指出:
聚合元素的初始化按元素顺序进行评估。也就是说,与给定元素相关的所有值计算和副作用都按顺序排列在其后面的任何元素的计算和副作用之前。
这向我表明该行唯一正确的行为如下:
Pair。.x通过调用初始化成员X::X()co_await表达式(调用await_ready和await_suspend);暂停。然后,如果协程恢复,我期望:
await_resume服务员。.y通过调用初始化成员Y::Y(int)Pair::~Pair()临时销毁。如果协程被破坏,我预计:
X::~X()给.x会员。我相当确定这是正确的行为,尽管不太确定这是否是唯一允许的行为 - 而且我的困惑由于没有一个主要编译器针对这种情况输出合理的代码而变得更加严重。godbolt 上的完整示例表明,gcc 和 clang 生成的代码中对析构函数和构造函数的调用不正确匹配(这是我首先在 gcc 中寻找的错误)。MSVC 给出内部编译器错误。
建议的行为正确吗?这是唯一正确的行为吗?
我正在编写一些代码,并且有一个带有self按值获取方法的特征。我想在一个Box'd trait 对象上调用这个方法(消耗Box和它的值)。这可能吗?如果是这样,如何?
在代码方面,一个最小的例子看起来像以下(不完整的)代码:
trait Consumable {
fn consume(self) -> u64;
}
fn consume_box(ptr: Box<dyn Consumable>) -> u64 {
//what can I put here?
}
Run Code Online (Sandbox Code Playgroud)
我的问题是如何在功能填补consume_box与指定的签名,以便值返回的任何值将通过调用得到consume的Box“d值。
我最初写的
ptr.consume()
Run Code Online (Sandbox Code Playgroud)
作为函数的主体,虽然我意识到这不是一个正确的想法,因为它没有理解我想要Box被消耗的事实,而不仅仅是它的内容,但这是我唯一能想到的. 这不会编译,给出一个错误:
无法移动 dyn Consumable 类型的值:无法静态确定 dyn Consumable 的大小
这对我来说有点令人惊讶,我是 Rust 的新手,我曾想过可能self参数的传递类似于 C++ 中的右值引用(这确实是我想要的 - 在 C++ 中,我可能会通过带有签名的方法来实现它virtual std::uint64_t consume() &&,让std::unique_ptr通过虚拟析构函数清理移动的对象),但我猜 Rust 确实是按值传递,将参数移动到位之前 - 所以它拒绝代码是合理的。
问题是,我不确定如何获得我想要的行为,在那里我可以使用Box'd trait 对象。我尝试使用默认实现向 trait 添加一个方法,认为这可能会让我在 …