我正在用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字段bar将被构造为指向foo中的Some值,如果存在None,则为空指针。
当然,这里的问题是,如果要移动Cached的值,那么直接的memcpy将是不合适的,而且bar.p_foo还需要重定向。这在C++中很容易确保,因为它具有可定义的移动语义,但是Rust除了提供“在使用之前不要设置bar.p_foo”之外,还提供了一个解决方案吗?虽然这样做肯定会奏效,但我不认为这些缓存的值会被移动得超过(甚至接近于重复使用的频率),并且需要做一些工作来设置这些指针,特别是在嵌套/链接很深/很长的情况下。我也不希望堆上的子结构是Box。
为了澄清,下面是我可以用C++编写的东西,我想在Rust中复制它:
struct Foo {
int x;
float y;
};
struct Bar {
Foo const*pFoo;
bool z;
};
// bear with me while I conjure up a Maybe for C++
class Cached {
public:
// would have appropriate copy constructor/assignment
Cached(Cached &&other) {
m_foo = other.m_foo;
m_bar = other.m_bar;
if(m_foo.isJust()) {
m_bar.pFoo = &m_foo.value();
} // else already nullptr
}
// similar move assignment
private:
Maybe<Foo> m_foo;
Bar m_bar;
};发布于 2016-03-24 08:33:00
锈蚀等效是不使用原始指针,因为原始指针是为了实现我们的安全数据结构,而不是实现正常的数据结构。
#[repr(C)]
struct Foo {
x: i32,
y: f32
}
#[repr(C)]
struct Bar {
p_foo: Option<Box<Foo>>,
z: bool
}只要Option<Box<T>>是一种类型,而不是一种特征,则保证*const T与*const T完全等价(以内存中的位为单位)。唯一的区别是在锈病中使用是安全的。
这样,您甚至不再需要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,
}
}
}要设置这些指针需要做一些工作,特别是如果嵌套/链接很深/很长的话。
这听起来很像是过早的优化。不要在没有设定基准的地方进行优化。
https://stackoverflow.com/questions/36188870
复制相似问题