如何将值从参数中移出 Drop::drop()? [英] How can I move a value out of the argument to Drop::drop()?
问题描述
我正在使用 gfx-hal
,这要求我创建需要使用特定于其类型的函数显式销毁的资源.我想将这些类型的实例存储在结构中,并且我还想将清理它们与拥有结构的生命周期联系起来,而不是手动管理它们的生命周期并可能在 GPU/驱动程序中拥有对象永远.
I'm using gfx-hal
, which requires me to create resources which need to be explicitly destroyed using functions specific to their type. I'd like to store instances of these types in structs, and I'd also like to tie cleaning them up to the lifetime of the owning struct, instead of managing their lifetimes manually and potentially having objects on the GPU/in the driver live forever.
但是,destroy
函数系列中的所有函数都直接采用类型,而不是引用,因此当我尝试从结构中传递它们时,会出现如下错误:
However, all the functions in the destroy
family of functions take the type directly, rather than a reference, so when I try to pass them from my structs, I get errors like the following:
error[E0509]: cannot move out of type `S`, which implements the `Drop` trait
--> src/lib.rs:9:18
|
9 | destroyT(self.member)
| ^^^^^^^^^^^ cannot move out of here
似乎应该有办法解决这个问题,因为我目前在 Drop::drop
函数本身中,所以 self
已经被消耗了."如何从 self
中获取这些类型的实例作为 T
,而不是 &T
?
It seems like there should be some way around this issue, as I'm currently in the Drop::drop
function itself, so self
is already "consumed." How do I get the instances of these types out of self
as T
, and not &T
?
struct T;
struct S {
member: T,
}
impl Drop for S {
fn drop(&mut self) {
destroyT(self.member)
}
}
// elsewhere, in a library
fn destroyT(t: T) {
//...
}
推荐答案
最安全、最简单的方法是使用Option
:
The safest, easiest way to do this is to use an Option
:
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: Option<T>,
}
impl Drop for S {
fn drop(&mut self) {
if let Some(t) = self.member.take() {
destroy_t(t);
}
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S { member: Some(T) };
}
<小时>
您可以选择使用带有 ManuallyDrop的不安全代码代码>
和将当前值换成未初始化的1:
use std::mem::{self, ManuallyDrop};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<T>,
}
impl Drop for S {
fn drop(&mut self) {
unsafe {
let valid_t = mem::replace(&mut *self.member, mem::uninitialized());
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
};
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
1 使用 mem::uninitialized
是极其危险且难以获得对,特别是在一般情况下.使用夜间 MaybeUninit
,这可能看起来像
1 Using mem::uninitialized
is extremely dangerous and hard to get right, especially in generic contexts. Using the nightly MaybeUninit
, this might look like
#![feature(maybe_uninit)]
use std::mem::{self, ManuallyDrop, MaybeUninit};
struct T;
impl Drop for T {
fn drop(&mut self) {
println!("dropping T");
}
}
struct S {
member: ManuallyDrop<MaybeUninit<T>>,
}
impl Drop for S {
fn drop(&mut self) {
let invalid_t = MaybeUninit::uninitialized();
let valid_t = mem::replace(&mut *self.member, invalid_t);
let valid_t = unsafe { valid_t.into_inner() };
destroy_t(valid_t);
// do *not* call ManuallyDrop::drop
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(MaybeUninit::new(T)),
};
}
另见:
这篇关于如何将值从参数中移出 Drop::drop()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!