【问题标题】:Reuse raw pointer to rehydrate Rust Box重用原始指针来补充 Rust Box
【发布时间】:2021-03-10 12:18:49
【问题描述】:

我有一个函数可以将Box::into_raw 结果转换为u64。我后来're-Box'来自u64

// Somewhere at inception
let bbox = Box::new(MyStruct::from_u32(1u32).unwrap());
let rwptr = Box::into_raw(bbox);
let bignum_ptr = rwptr as u64;

// Later in life
let rehyrdrate: Box<MyStruct> = unsafe {
    Box::from_raw(bignum_ptr as *mut MyStruct)
};

我想做的是根据需要一次又一次地're-Box'bignum_ptr。这可能吗?

【问题讨论】:

  • rehydrate 超出范围时会发生什么?分配给盒子的内存是否应该被释放?
  • bignum_ptr 的持有者将负责丢弃,
  • 在这种情况下,rehydrate 应该是参考,而不是框:let rehyrdrate: &amp;MyStruct = unsafe { &amp;*(bignum_ptr as *const MyStruct) };。当您需要释放该框(并且知道不存在未完成的引用)时,您可以使用drop(Box::from_raw(bignum_ptr as *mut MyStruct))
  • @user4815162342 谢谢...我会试试看!
  • 很少有任何理由将原始指针转换为整数,但如果必须(某些 FFI 要求),您应该使用 usize 而不是 u64

标签: rust


【解决方案1】:

一个盒子拥有它指向的数据,当它超出范围时会释放/删除它,所以如果你需要在多个地方使用相同的指针,Box 不是正确的类型。要支持指针的多次“复活”,您可以使用引用来代替:

// safety contract: bignum_ptr comes from a valid pointer, there are no
// mutable references
let rehydrate: &MyStruct = unsafe { &*(bignum_ptr as *const MyStruct) };

当需要释放初始框及其数据时(并且您知道不存在未完成的引用),然后才使用Box::from_raw 重新创建框:

// safety contract: bignum_ptr comes from a valid pointer, no references
// of any kind remain
drop(unsafe { Box::from_raw(bignum_ptr as *const MyStruct) });

【讨论】:

  • 正如我在answer 中提到的,不能保证可以通过整数往返;它可能会或可能不会在未来得到保证,但我们还不知道,即使它现在恰好可以工作。一般来说,将指针转换为整数的理由很少。
  • @Acorn 这个代码破坏会破坏 很多 其他代码(包括几乎所有 FFI),所以除非你能在 Rust 的上下文中提出具体的引用,否则我找不到您的答案相关。我同意的部分是指针适合u64 的假设;我会改用usize
  • 另外,通过 u64 的往返只是问题的一小部分,问题的要点和答案与所有​​权相关。关于 u64 往返的评论可能属于 cmets 的问题,而不是这里。
  • 这种代码破坏确实意味着 FFI 代码必然会破坏。你有责任想出一个说这的声音,因为这是你的答案。无论如何,这个语言区域仍在设计中,所以一个人无法分辨出哪一种方式,这就是问题所在。
  • Re:通过整数往返并不是小问题,因为它会使整个事情变得不健全。问题很清楚地指出这是通过第一句话中的u64 完成的。
【解决方案2】:

我想做的是根据需要,一次又一次地“重新装箱”那个 bignum_ptr。这可能吗?

如果你的意思是从同一个指针创建多个盒子而不是每次都取出它,不是。

如果您的意思是反复输入和输出,并且每次都通过整数往返,可能是的;但是,我会小心使用这样的代码。它很可能会起作用,但请注意,Rust 的内存模型尚未正式化,并且指针出处的规则将来可能会发生变化。即使是 C 和 C++ 标准(Rust 内存模型的来源)也有围绕这些问题的悬而未决的问题,包括通过整数类型的往返。

此外,您的代码假定指针适合 u64,这可能适用于大多数架构,但未来可能并非全部。

至少,我建议你使用mem::transmute 而不是演员。


简而言之:不要这样做。对于您想要实现的目标,可能会有更好的设计。

【讨论】:

  • 必须以某种形式支持这种代码(以 cmets 中讨论的生命周期为模)才能使 FFI 工作。将原始指针发送到外部 C 函数并返回与上述相同。
  • @user4815162342 通常,您将通过*mut*const 发送指针,而不是通过整数。即使使用整数,Rust 也可以允许它用于 FFI,但不允许通过整数类型进行“本地”往返。
  • @Acorn - 明白了......这个应用程序是针对区块链的,所以在短期内它不是问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
  • 2019-06-30
  • 2013-04-25
相关资源
最近更新 更多