使用闭包从 Option<&T 获取原始指针是否安全>?



我有一个Option<&T>,我想有一个原始*const T如果选项None,则为空。我想包装一个 FFI 调用,该调用将指针指向 Rust 分配的对象。

此外,我使用的 FFI 接口具有借用语义(我分配一些东西并传递指向它的指针),而不是所有权语义

extern "C" {
// Parameter may be null
fn ffi_call(*const T);
}
fn safe_wrapper(opt: Option<&T>) {
let ptr: *const T = ???;
unsafe { ffi_call(ptr) }
}

我可以使用match语句来执行此操作,但这种方法感觉非常冗长。

let ptr = match opt {
Some(inner) => inner as *const T,
None => null(),
};

我还可以将引用映射到指针,然后使用unwrap_or.

let ptr = opt.map(|inner| inner as *const T).unwrap_or(null());

但是,我担心指针在通过闭包时可能会失效。Rust 是否保证最终指针将指向与原始引用相同的内容?如果TCopy,这是否以有意义的方式改变了语义?有没有更好的方法被我忽略了?

是的,这是安全的。我会把它写成:

use std::ptr;
fn safe_wrapper(opt: Option<&u8>) {
let p = opt.map_or_else(ptr::null, |x| x);
unsafe { ffi_call(p) }
}

如果你发现自己写了很多,你可以把它变成一个特征,并将其简化为一个方法调用。

指针在通过闭包时可能会失效

可能是,如果你自己以某种方式使它无效。因为函数接受引用,所以你肯定知道引用的值在函数调用期间有效——这就是 Rust 借用检查器的目的。

指针无效的唯一方法是更改指针的值(例如,向其添加偏移量)。既然你不这样做,那就没关系。

Rust 是否保证最终指针将指向与原始引用相同的内容?

这取决于你所说的"最终"是什么意思。将引用转换为指针将始终导致两个值在内存中包含相同的位置。其他任何事情都是故意恶意的,没有人会一开始就使用 Rust。

如果TCopy,这是否以有意义的方式改变了语义?

不。此外,我们正在谈论一个&T,它总是Copy

另请参阅:

  • 将选项<和mut T=">转换为*mut T
  • 我们应该使用 Option 或 ptr::null 来表示 Rust 中的空指针吗?
  • 在 FFI 中使用 ptr::NonNull 是否有效?

我使用的 FFI 接口具有借用语义(我分配某些东西并传递指向它的指针),而不是所有权语义

需要明确的是,您不能仅根据函数类型来确定所有权。

此 C 函数获得所有权:

void string_free(char *)

这个 C 函数借用:

size_t string_len(char *)

两者都指了指点。Rust 通过清楚地描述什么是借款和什么是所有权转让来改善这种情况。

extern "C" {
// Parameter may be null
fn ffi_call(*const T);
}

此代码是无意义的;它没有定义泛型类型T并且 FFI 函数无论如何都不能具有泛型类型。

最新更新