c - 如何在不泄漏内存的情况下将 Rust 结构和方法实现为 C 中的 Vec?

标签 c struct binding rust ffi

我在写 Rust bindings对于使用嵌入式构造函数和析构函数的 C 库。 C头的原始Rust代码:

// Opaque structures transform to enumerate
pub enum UdbEntity_ {}
pub enum UdbReference_ {}
...
pub type UdbEntity    = *mut UdbEntity_;
pub type UdbReference = *mut UdbReference_;
...

// Return a non-allocated, permanent list of all entities. This list may be
// used in places where an allocated entity list is required and may be
// safely passed to udbListEntityFree().
pub fn udbListEntity(list: *mut *mut UdbEntity, items: *mut c_int);

// Free an allocated list of entities.
pub fn udbListEntityFree(list: *mut UdbEntity);
...

// Return an allocated list of all references for entity.
// Free the list with udbListReferenceFree().
pub fn udbListReference(entity : UdbEntity,
                        refs   : *mut *mut UdbReference,
                        items  : *mut c_int);

// Free the allocated references list.
pub fn udbListReferenceFree(refs: *mut UdbReference);

这是安全 Rust 代码的实现,如 git2-rs :

/// Structure of Entity.
pub struct Entity<'ents> {
    raw: UdbEntity,
    _marker: PhantomData<&'ents UdbEntity>,
}

/// Opaque structure of list of entities.
pub struct ListEntity<'db> {
    raw: *mut UdbEntity,
    len: usize,
    _marker: PhantomData<&'db Db>,
}

/// An iterator over the Entity in list of entities.
pub struct EntityIter<'ents> {
    range: Range<usize>,
    ents: &'ents ListEntity<'ents>,
}

impl<'db> Drop for ListEntity<'db> {
    fn drop(&mut self) {
        unsafe { udbListEntityFree(self.raw) };
    }
}

对于 ListReferenceReference也是。

我需要使用 ListEntityVec<Entity> 一样(迭代器,用于排序的切片等),但我无法实现它。在我的实现版本中,我无法创建切片:from_raw_parts返回 UdbEntity 上的切片, 不是 Entity .

当我保持 Vec<Entity>EntityList稍后当我编辑 Vec<Entity> 时(移动它),EntityList被删除并释放分配列表 *mut UdbEntity .我也需要正确的生命周期。

我颠倒了一些简单的结构(例如 KindListKind)来编写纯 Rust 代码,但我认为存在更惯用的路径。

最佳答案

问题是您的代码中有两个相当不相交的结构。一方面,您有一个 ListEntity,它拥有 UdbEntity 的原始数组并在需要时释放它,另一方面,您有一个 Entity 它包装了 UdbEntity,但未以任何方式在 ListEntity 中引用。

这里有两个选择。

  1. UdbEntity 数组转换为 Entity 数组,在这种情况下,您将能够创建它的切片。为此,它们需要具有相同的内存表示。
  2. UdbEntity 中单独创建一个 Entity vector ,然后返回它们。

假设第一种方法是安全的,我会接受。如果没有,那么第二个可以工作。在这两种情况下,Entity 的数组都应归 ListEntity 所有,以便正确管理内存。我可能会放弃 Entity 中的 PhantomData 并简单地返回对它们的引用。

关于c - 如何在不泄漏内存的情况下将 Rust 结构和方法实现为 C 中的 Vec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39325701/

相关文章:

java - Android XML 绑定(bind) - Simpleframework

c - "loop_until_bit_is_set"宏和 while() 表达式之间的区别

c - 尝试为结构中的字符串分配内存时出现段错误

Android 服务 onBind -> onStart

c# - 还有其他类似的 ObservableCollection<T> 吗?

从 argv、树 trie 复制时核心被转储

c - STM32F4 PWM和中断用同一个定时器

c - 在 20 层有约束条件下爬 n 层楼梯的可能性

c - 为什么在C程序中变量被突变?

go - 包的类型不能用作 vendored 包的类型