我正在使用gfx-hal,这需要我创建需要使用特定于其类型的函数显式销毁的资源.我想将这些类型的实例存储在结构中,并且我还希望将它们清理到拥有结构的生命周期,而不是手动管理它们的生命周期并且可能在GPU上/驱动程序中有对象永远.
但是,函数destroy族中的所有函数都直接使用类型而不是引用,所以当我尝试从结构中传递它们时,会出现如下错误:
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
Run Code Online (Sandbox Code Playgroud)
似乎应该有一些解决这个问题的方法,因为我目前处于Drop::drop函数本身,因此self已经"消耗"了.我如何获得这些类型的实例出来self的T,而不是&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) {
//...
}
Run Code Online (Sandbox Code Playgroud)
在最安全的要做到这一点,最简单的方法是使用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) };
}
Run Code Online (Sandbox Code Playgroud)
您可以选择使用不安全的代码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),
};
}
Run Code Online (Sandbox Code Playgroud)
1使用mem::uninitialized是非常危险的,很难得到正确,特别是在一般的环境中.使用夜间MaybeUninit,这可能看起来像
#![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)),
};
}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
您可以使用ManuallyDrop。它没有任何开销并且有清晰的 API。它使用起来不那么痛苦,MaybeUninit因为它不需要unsafe在其他地方使用(可以通过 simple 访问内部值Deref)并且只需要unsafe实际将值移出。
use std::mem::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) {
// SAFETY: this is safe because we do not access `self.member` any more
let member = unsafe { ManuallyDrop::take(&mut self.member) };
destroy_t(member);
// dropping a `ManuallyDrop` does nothing
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
Run Code Online (Sandbox Code Playgroud)
use std::mem::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) {
// SAFETY: this is safe because we do not access `self.member` any more
let member = unsafe { ManuallyDrop::take(&mut self.member) };
destroy_t(member);
// dropping a `ManuallyDrop` does nothing
}
}
fn destroy_t(_t: T) {
println!("destroy T");
}
fn main() {
let _x = S {
member: ManuallyDrop::new(T),
};
}
Run Code Online (Sandbox Code Playgroud)
请记住,正如名称所示,ManuallyDrop将阻止内部值被删除,除非调用ManuallyDrop::take或ManuallyDrop::into_inner(从而将其从保护中删除,并且将应用正常的删除规则)或ManuallyDrop::drop使用 if 。