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

时间:2019-03-24 04:14:05

标签: rust

我有一个Option<&T>,并且我想有一个原始的*const T,如果选项为None,则为null。我想包装一个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,这是否以有意义的方式改变了语义?我有更好的方法可以忽略吗?

1 个答案:

答案 0 :(得分:2)

是的,这很安全。我将其写为:

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,这是否以有意义的方式改变了语义?

不。此外,我们谈论的是{strong>始终 &T

Copy

另请参阅:


  

我使用的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函数也不能具有通用类型。