使用cxx实现Rust与C++ FFI时Pin相关健全性及使用问题
问题1:Pin::new_unchecked 调用的健全性
你这里的写法是健全的,理由如下:
- cxx绑定的所有C类型默认都实现了
!Unpin,也就是无法在Rust侧安全移动,必须通过Pin包裹才能调用可变方法,完全符合C对象的内存语义。 - 你返回的
Row是Table的内嵌成员,C++中只要父对象本身的内存地址不发生移动,内嵌成员的地址就永远稳定。而你传入的Pin<&'a mut Table>已经保证了Table在生命周期'a内不会被移动,因此内部Row的地址在'a内也完全稳定。 - 官方文档提到的不安全场景是指:你
Pin了&'a mut T之后,在生命周期'a结束后仍然持有T的所有权并移动它,导致之前Pin的承诺失效。但你这里Row的生命周期完全和父对象Table的'a绑定,生命周期结束后你不可能再访问到这个Row实例,因此不存在违规风险。
问题2:连续调用方法的所有权问题
这个错误是因为Pin<&mut T>没有实现Copy trait,而set_value方法的接收者是值传递的self: Pin<&mut Row>,调用时会直接消费掉row变量。
有两种简单的解决方案:
方案1:调用时使用Pin::as_mut方法重借
Pin<&mut T>的as_mut()方法可以生成一个新的临时Pin<&mut T>,不会消费原来的变量,修改main函数的调用逻辑即可:
fn main() { let mut table = ffi::make_table(); let row = table.pin_mut().get_row_ref(); let_cxx_string!(hello="hello world"); row.as_mut().set_value(&hello); // 用as_mut重借,不消费row let_cxx_string!(hello2="bye world"); row.as_mut().set_value(&hello2); // 可以继续使用row }
方案2:不提前缓存Row引用,每次需要时直接获取
如果你不需要长期持有Row引用,也可以每次调用方法前临时获取,完全规避所有权问题:
fn main() { let mut table = ffi::make_table(); let_cxx_string!(hello="hello world"); table.pin_mut().get_row_ref().set_value(&hello); let_cxx_string!(hello2="bye world"); table.pin_mut().get_row_ref().set_value(&hello2); }
两种方案都完全符合cxx的约束,不需要修改绑定定义和C++代码。
内容的提问来源于stack exchange,提问作者harmic
相关产品推荐
相关产品推荐

