在 C 管理的内存中正确存储 Rust Rc<T>

Correctly storing a Rust Rc<T> in C-managed memory

我正在包装一个 Rust 对象以供 Lua 使用。当 Rust 代码和 Lua 都没有对它的引用时,我需要销毁对象,所以(对我来说)显而易见的解决方案是使用 Rc<T>,存储在 Lua-managed内存。

Lua API(我现在使用 rust-lua53)让你分配一块内存并附加方法和终结器,所以我想存储Rc<T> 进入那块内存。

我目前的尝试看起来像。一、创建对象:

/* Allocate a block of uninitialized memory to use */
let p = state.new_userdata(mem::size_of::<Rc<T>>() as size_t) as *mut Rc<T>;
/* Make a ref-counted pointer to a Rust object */
let rc = Rc::<T>::new(...);
/* Store the Rc */
unsafe { ptr::write(p, rc) };

在终结者中:

let p: *mut Rc<T> = ...; /* Get a pointer to the item to finalize */
unsafe { ptr::drop_in_place(p) };  /* Release the object */

现在这似乎可以工作了(通过向 drop 方法添加 println!() 进行了简短测试)。但它是否正确和安全(只要我确保它在完成后不被访问)?我对不安全的 Rust 没有足够的信心来确定 ptr::write 和 Rc<T>.

是可以的

我也想知道,与其直接存储一个 Rc<T>,不如存储一个 Option<Rc<T>>;那么我会用 None ptr::swap() 而不是 drop_in_place()。这将使最终确定后的任何使用都变得容易。

Now this seems to work (as briefly tested by adding a println!() to the drop method). But is it correct and safe (as long as I make sure it's not accessed after finalisation)? I don't feel confident enough in unsafe Rust to be sure that it's ok to ptr::write an Rc<T>.

是的,您可以 ptr::write 任何 Rust 类型到任何内存位置。这个"leaks" Rc<T> 对象,但是写了一个bit-equivalent 到目标位置。

使用它时,您需要保证没有人在 Rust 代码之外修改它,并且您仍然与创建它的线程处于同一线程中。如果你想能够跨线程移动,你需要使用Arc.

Rust 的线程安全在这里无法保护你,因为你使用的是原始指针。


I'm also wondering about, rather than storing an Rc<T> directly, storing an Option<Rc<T>>; then instead of drop_in_place() I would ptr::swap() it with None. This would make it easy to handle any use after finalisation.

ptr::write 的吊坠是 ptr::read。因此,如果您可以保证没有人尝试 ptr::readdrop_in_place() 对象,那么您可以调用 ptr::read (returns 对象)并将该对象用作您将使用任何其他 Rc<T> 对象。你不需要关心掉落或其他任何事情,因为现在它又回到了 Rust 的控制之下。


您还应该使用 new_userdata_typed 而不是 new_userdata,因为这样可以减轻您的内存处理负担。对于大多数用户数据需求,还有其他以后缀 _typed 结尾的便利包装函数。

您的代码将有效;当然,请注意 drop_in_place(p) 只会减少 Rc 的计数器,并且仅当且仅当它是最后一个引用时才删除包含的 T,这是正确的操作。