gpt4 book ai didi

rust - 从实现Drop的结构中移动值时,如何避免不必要的匹配检查或使用不安全?

转载 作者:行者123 更新时间:2023-12-03 11:39:54 26 4
gpt4 key购买 nike

我具有B结构,该结构使用Trait方法实现了特征do_something。如果尚未调用struct B,则需要执行一些其他操作。具体来说,如果从未调用过do_something,则Vec<A>应该用A::None填充:

enum A {
V1,
V2,
None,
}

struct B {
data: Option<(A, Vec<A>)>,
}

trait Trait {
fn do_something(self) -> Vec<A>;
}

impl Trait for B {
fn do_something(mut self) -> Vec<A> {
let (a, mut vec) = self.data.take().unwrap();
vec.push(a);
vec
}
}

impl Drop for B {
fn drop(&mut self) {
match self.data.take() {
Some((a, mut vec)) => vec.push(A::None),
_ => {}
}
}
}

在逻辑上这有一些不必要的 match检查。我想避免它们,并提出以下解决方案:

struct B {
data: (A, Vec<A>),
}

trait Trait {
fn do_something(self) -> Vec<A>;
}

impl Trait for B {
fn do_something(mut self) -> Vec<A> {
let (a, mut vec) = std::mem::replace(&mut self.data, unsafe {
std::mem::MaybeUninit::<(A, Vec<A>)>::uninit().assume_init()
});
std::mem::forget(self);
vec.push(a);
vec
}
}

impl Drop for B {
fn drop(&mut self) {
self.data.1.push(A::None)
}
}
  • 我的unsafe解决方案正确吗?它是否包含未定义的行为?
  • 是否可以避免使用unsafe或将B.data包装在Option中来实现上述行为?
  • 最佳答案

    这不仅将值移出结构,还将未初始化的内存写入结构。编译器警告这将导致未定义的行为:

    warning: the type `(A, std::vec::Vec<A>)` does not permit being left uninitialized
    --> src/main.rs:21:22
    |
    21 | unsafe { std::mem::MaybeUninit::<(A, Vec<A>)>::uninit().assume_init() },
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | |
    | this code causes undefined behavior when executed
    | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
    |
    = note: `#[warn(invalid_value)]` on by default
    note: std::ptr::Unique<A> must be non-null (in this struct field)

    更好的解决方案是使用 mem::transmute():
    #[repr(transparent)]
    struct B {
    data: (A, Vec<A>),
    }

    impl Trait for B {
    fn do_something(self) -> Vec<A> {
    // Safety: Since `B` is transparent, `B` and (A, Vec<A>) have the same size and layout.
    let (a, mut vec): (A, Vec<A>) = unsafe { std::mem::transmute(self) };
    vec.push(a);
    vec
    }
    }

    请注意,这可以防止 Drop被调用。如果 Drop实现释放了内存或其他资源,则必须手动执行此操作。

    关于rust - 从实现Drop的结构中移动值时,如何避免不必要的匹配检查或使用不安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60394139/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com