如何将值从参数中移出 Drop::drop()? [英] How can I move a value out of the argument to Drop::drop()?

查看:72
本文介绍了如何将值从参数中移出 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆