如何在 Rust 中获取 C 指针的所有权并适当地删除它?



我正在调用一个 C 构造函数keyNew,该函数为Key结构分配内存并向 Rust 端返回*mut Key。使用Box::from_raw来包装指针并取得其所有权是否合适?

我也可以直接返回原始指针,但这会使 API 变得非常丑陋,并且对 Rust 来说不是惯用的。

我还想在键上实现 Drop Trait,以便自动调用析构函数keyDel,这将是对 C 中手动调用的改进。在我看来,这是一个更好的API。但是,实现删除特征要求不实现复制特征,因此由于"移出取消引用的内容",不再可能取消引用原始指针。

他们钥匙是由锈结合剂产生的

#[repr(C)]
#[derive(Debug, Clone)]
pub struct Key {
_unused: [u8; 0],
}

Key的构造函数是这样实现

fn new() -> Box<Key> {
unsafe { Box::from_raw(keyNew(0 as *const i8)) }
}

和析构函数

impl Drop for Key {
fn drop(&mut self) {
unsafe { keyDel(self) };
}
}

这一切都非常有效,由于 Deref,我可以使用像Key这样的Box<Key,并且当Box<Key从 scpe 中消失时会自动调用keyDel。但是我不确定这是否合适,因为 Rust 文档对Box::from_raw有这样的说法

调用此函数后,原始指针归生成的 Box 所有。具体来说,Box 析构函数将调用 T 的析构函数并释放分配的内存。由于 Box 分配和释放内存的方式未指定,因此传递给此函数的唯一有效指针是通过 Box::into_raw 函数从另一个 Box 获取的指针。

我以后不会打电话给Box::into_raw,那么这一切在记忆方面仍然有效吗?如果没有,还有什么替代方法来获得返回*mut Key的所有权?

使用 Box::from_raw 来包装指针并取得它的所有权是否合适?

from_raw的文档为您解答了这个问题:

由于 Box 分配和释放内存的方式未指定,因此传递给此函数的唯一有效指针是通过Box::into_raw函数从另一个 Box 获取的指针。

这意味着您当前的使用情况未指定。

我还想在键上实现 Drop Trait,以便自动调用析构函数 keyDel

你不应该为Key实现DropKey因为 Rust 没有分配。理想情况下,您将创建自己的包装器类型,该包装器类型使用自己的drop通过指针调用keyDel。例如:

struct KeyWrapper {
ptr: NonNull<Key>
}
impl Drop for KeyWrapper {
fn drop(&mut self) {
keyDel(self.ptr.as_ptr())
}
}
impl KeyWrapper {
fn new() {
KeyWrapper {
ptr: NonNull::new(keyNew(0 as *const i8))
}
}
fn someUtil(&self) {
// As an example, you could call through to some C function.
keySomeUtil(self.ptr.as_ptr())
}
}

这样,在 Rust 端,您只与包装指针的类型进行交互,并且在删除指针时它将调用keyDel。你的工作是确保这个包装器类型只通过 C API 执行安全操作,以免使 Rust 的安全保证失效。

相关:

  • 如何强制 Rust 获得分配的内存的所有权,而不是通过其安全方法?

最新更新