【问题标题】:Is it safe to use a closure to get a raw pointer from an Option<&T>?使用闭包从 Option<&T> 获取原始指针是否安全?
【发布时间】:2019-08-14 16:23:09
【问题描述】:

我有一个Option&lt;&amp;T&gt;,我想要一个原始的*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,这是否会以有意义的方式改变语义?有没有更好的方法让我忽略?

【问题讨论】:

  • @Stargateur 我将最终使用unsafe 通过指针操作T。此外,我使用的 FFI 接口具有借用语义(我分配了一些东西并传递了一个指向它的指针),而不是所有权语义,所以&amp; 似乎比Box 更好。这个问题是关于构造指针的,这是一个安全的操作。我的主要问题是:如何确保生成的指针实际上指向与引用相同的东西?

标签: rust


【解决方案1】:

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

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

没有。此外,我们谈论的是&amp;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 函数无论如何也不能有泛型类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-01
    • 2016-11-23
    • 2015-03-17
    • 1970-01-01
    • 2015-10-14
    • 2023-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多