我正在与一些使用标准void* userdata方法的C回调进行交互,以允许您存储对某些上下文(例如struct)的引用。如何在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);
}
Run Code Online (Sandbox Code Playgroud)
有没有解决的办法?我能否拥有一个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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您尝试使用同时移动或复制构造的对象的地址,则在C ++中会遇到相同的问题。
一个警告:实际上使用指针将导致未定义的行为,除非采取预防措施以防止对同一对象存在多个可写引用。该UnsafeCell文件说:
通常,将
&T类型转换为会&mut T被视为未定义行为。编译器基于&T不会可变别名或突变且&mut T唯一的知识进行优化。
box可能更安全RefCell<RealThing>,将不变的指针存储到装箱的单元格,然后&mut RealThing通过将指针转换为引用&RefCell<RealThing>并调用borrow_mut()引用,将其转换回。如果您随后犯了一个错误,至少Rust会惊慌地警告您。
| 归档时间: |
|
| 查看次数: |
497 次 |
| 最近记录: |