在Rust

时间:2016-03-23 21:18:53

标签: rust move-semantics ffi dangling-pointer

我在Rust中包装了一个C库,它的许多函数通过指向结构的指针来获取参数,这些结构本身通常具有指向其他结构的指针。为了减少开销,我希望能够将将Rust数据编组的结果缓存到C结构中。

以下是C库如何期望某些参数的示例:

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar {
    p_foo: *const Foo,
    z: bool
}

我如何想象一个拥有,"缓存"版本看起来:

struct Cached {
    foo: Option<Foo>,
    bar: Bar
}

p_foo的{​​{1}}字段将构建为指向bar内的Some值,如果存在foo则指向空指针。

这个问题当然是,如果要移动None的值,则直接Cached将不合适,并且memcpy还需要重定向。这在C ++中很容易确保,具有可定义的移动语义,但Rust除了提供bar.p_foo之外还提供了一个解决方案,直到它被使用&#34;?虽然这样做肯定会有效,但我不能想象这些缓存的值会被移动超过(甚至接近它们被重用的频率),并且需要进行一些工作来设置这些指针,特别是如果嵌套/链接是深/长。我还不是bar.p_foo堆上的子结构。

澄清一下,这里是我用C ++编写的内容,我想在Rust中复制:

Box

1 个答案:

答案 0 :(得分:1)

Rust等效的是不使用原始指针,因为原始指针用于实现我们的安全数据结构,而不是用于实现普通数据结构。

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar {
    p_foo: Option<Box<Foo>>,
    z: bool
}

Option<Box<T>>保证与*const T完全等效(在内存中的位数),只要T是类型而不是特征。唯一的区别是在Rust中使用它是安全的。

这样您甚至不再需要Cached结构,但可以直接传递Bar对象。

  

我也不愿意在堆上装箱子结构。

然后我建议你不要留下Bar物品,而是在需要将一个物品传递给C时召唤它:

#[repr(C)]
struct Foo {
    x: i32,
    y: f32
}

#[repr(C)]
struct Bar<'a> {
    p_foo: Option<&'a Foo>,
    z: bool
}

struct Cached {
    foo: Option<Foo>,
    z: bool,
}

impl Cached {
    fn bar<'a>(&'a self) -> Bar<'a> {
        Bar {
            p_foo: self.foo.as_ref(),
            z: self.z,
        }
    }
}
  

设置这些指针需要做一些工作,特别是如果嵌套/链接是深/长的话。

这听起来很像过早优化。不要优化您尚未进行基准测试的地方。