Как я могу переместить значение из аргумента в Drop :: drop ()? - PullRequest
0 голосов
/ 12 ноября 2018

Я использую gfx-hal, что требует от меня создания ресурсов, которые должны быть явно уничтожены с использованием функций, специфичных для их типа. Я хотел бы хранить экземпляры этих типов в структурах, и я также хотел бы связать очистку их до времени существования структуры-владельца вместо того, чтобы управлять их временем жизни вручную и потенциально иметь объекты в графическом процессоре / в драйвере в режиме реального времени. навсегда.

Однако все функции семейства функций 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

Кажется, должен быть какой-то способ обойти эту проблему, так как я в настоящее время нахожусь в самой функции 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) {
    //...
}

1 Ответ

0 голосов
/ 12 ноября 2018

самый безопасный , самый простой способ сделать это - использовать 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, это может выглядеть как

#![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)),
    };
}

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...