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

时间:2016-03-10 12:38:32

标签: rust ffi

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

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 ::写一个Rc<T>是可以的。

我也想知道,而不是直接存储Rc<T>,存储Option<Rc<T>>;然后我drop_in_place()而不是ptr::swap()而不是None。这样可以在最终确定后轻松处理任何用途。

2 个答案:

答案 0 :(得分:5)

  

现在这似乎有效(通过向drop方法添加println!()进行简要测试)。但它是否正确和安全(只要我确保它在最终确定后无法访问)?我不能对不安全的Rust感到自信,以确保ptr ::写Rc<T>是对的。

是的,您可以ptr::write任何内存位置的任何Rust类型。这&#34;泄漏&#34; Rc<T>对象,但写入相当于目标位置的位。

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

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

  

我也想知道,而不是直接存储Rc<T>,存储Option<Rc<T>>;然后我用ptr :: swap()代替drop_in_place()。这样可以在最终确定后轻松处理任何用途。

ptr::write的吊坠是ptr::read。因此,如果您可以保证没有人尝试ptr::readdrop_in_place()对象,那么您只需调用ptr::read(返回对象)并使用该对象,就像使用任何对象一样其他Rc<T>个对象。你不需要关心丢弃或任何东西,因为它现在又回到了Rust的控制之下。

您还应该使用new_userdata_typed而不是new_userdata,因为这会占用内存处理。对于大多数用户数据需求,还有其他便利包装函数以postfix _typed结尾。

答案 1 :(得分:1)

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