如何在 Rust 中存储对结构的 void* 引用?

2024-02-06

我正在与一些使用标准的 C 回调进行交互void* userdata方法允许您存储对某些上下文(例如结构)的引用。如何在 a 中存储对 Rust 结构的引用void*并且仍然允许它四处移动?看起来 Rust 的动作确实是动作,即这段代码失败了(正如预期的那样):

struct Thing {
    pointer_to_self: *mut Thing,
}

fn create_thing() -> Thing {
    let mut a = Thing {
        pointer_to_self: std::ptr::null_mut(),
    };
    a.pointer_to_self = &mut a as *mut _;
    a
}

fn main() {
    let mut b = create_thing();

    assert_eq!(&mut b as *mut _, b.pointer_to_self);
}

有没有解决的办法?我可以拥有一个在移动时不会更改地址的 Rust 值吗?


您可以通过堆分配对象来防止值更改地址。这将花费取消引用来访问它,但它将是固定的:

struct RealThing {
    // ...
}

struct Thing {
    // pointer could also be a field in RealThing, but it seems to
    // make more sense to leave only the actual payload there
    real_thing: Box<RealThing>,
    pointer_to_real: *mut RealThing,
}

fn create_thing() -> Thing {
    let mut a = Thing {
        real_thing: Box::new(RealThing {}),
        pointer_to_real: std::ptr::null_mut(),
    };
    a.pointer_to_real = a.real_thing.as_mut() as *mut _;
    a
}

fn main() {
    let mut b = create_thing();

    assert_eq!(b.real_thing.as_mut() as *mut _, b.pointer_to_real);
}

请注意,如果您尝试使用同时已移动或复制构造的对象的地址,则在 C++ 中也会遇到相同的问题。

警告一句:实际上using除非采取预防措施以防止同一对象存在多个可写引用,否则指针将导致未定义的行为。这UnsafeCell文档说:

一般来说,变换一个&T输入一个&mut T被认为是未定义的行为。编译器根据以下知识进行优化&T不是可变别名或变异的,并且&mut T是独特的。

装箱可能更安全RefCell<RealThing>,存储一个指向装箱单元格的不可变指针,并将其转换回&mut RealThing通过将指针投射到&RefCell<RealThing>并打电话borrow_mut()关于参考。如果你犯了一个错误,至少 Rust 会通过恐慌来警告你。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Rust 中存储对结构的 void* 引用? 的相关文章

随机推荐