使用 Drop trait 释放 repr(C) 结构的正确习惯用法

标签 c memory rust

这段代码运行良好,但在 Rust nightly (1.2) 上会给出编译器警告

#[repr(C)]
struct DbaxCell { 
    cell: *const c_void
}

#[link(name="CDbax", kind="dylib")] 
extern {
    fn new_dCell(d: c_double) -> *const c_void;
    fn deleteCell(c: *const c_void);
}

impl DbaxCell {
    fn new(x: f64) -> DbaxCell {
        unsafe {
            DbaxCell { cell: new_dCell(x) }
        }
    }
}

impl Drop for DbaxCell {
    fn drop(&mut self) {
        unsafe {
            deleteCell(self.cell);
        }
    }
}

它链接到 C 库并正确创建/删除单元对象。但是它会发出警告

src\lib.rs:27:1: 33:2 warning: implementing Drop adds hidden state to types, possibly conflicting with `#[repr(C)]`, #[warn(drop_with_repr_extern)] on by default
\src\lib.rs:27 impl Drop for DbaxCell {
\src\lib.rs:28     fn drop(&mut self) {
\src\lib.rs:29         unsafe {
\src\lib.rs:30             deleteCell(self.cell);
\src\lib.rs:31         }
\src\lib.rs:32     }

确保正确清理这些 DbaxCell 并且不发出警告的正确方法是什么?

最佳答案

我认为您将两个概念混为一谈。如果您希望结构的布局直接对应到结构的布局,则结构应该是 repr(C),因为 C 编译器会对其进行布局。也就是说,它具有相同的内存中 representation。

但是,如果您只是持有一个原始指针,并且不打算将持有结构传递回 C,那么您不需要。在这种情况下,简短的解决方案是“删除 repr(C)".

解释一下这个错误...

implementing Drop adds hidden state to types, possibly conflicting with #[repr(C)]

这已在 issue 24585 中讨论过.当一个对象被丢弃时,会设置一个隐藏标志(“状态”),指示该对象已被丢弃,从而防止发生多次丢弃。但是,隐藏位意味着您在 Rust 中看到的内容与在 C 中的结构字节不对应,这否定了 repr(C) 的目的。

作为 cribbed from @bluss :

Low level programmers, don't worry: future Rust will remove this drop flag entirely.

Use repr(C) to pass structs in FFI, and use Drop on "regular Rust" structs if you need to. If you need both, embed the repr(C) struct inside the regular struct.

假设我们有一个库,它公开了一个带有两个 8 位数字的 C 结构,以及获取和返回该结构的方法:

typedef struct {
    char a;
    char b;
} tuple_t;

tuple_t tuple_increment(tuple_t position);

在这种情况下,您肯定想模仿该结构并匹配 Rust 中的 C 表示:

#[repr(C)]
struct Tuple {
    a: libc::char,
    b: libc::char,
}

但是,如果库返回了指向结构的指针,并且您永远不需要插入它(结构是不透明),那么您无需担心 repr(C ):

void tuple_increment(tuple_t *position);

然后你可以使用那个指针并实现 Drop:

struct TuplePointer(*mut libc::c_void);

impl Drop for TuplePointer {
    // Call the appropriate free function from the library
}

关于使用 Drop trait 释放 repr(C) 结构的正确习惯用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30742004/

相关文章:

rust - 对零大小类型的引用之间的生命周期差异

c - 从当前目录中删除文件

c - 为什么这个 GtkFrame 没有边框?

c - 如何在 C 中释放 malloc 的二维数组?

c# - 无需先加载即可读取 tiff 文件的尺寸和分辨率

rust - 在请求守卫中访问 Rocket 0.4 数据库连接池

c - 在多文件程序和包含中,函数定义如何包含到主程序中?

c++ - 使用迭代器从 STL 列表中删除 C++ 结构

Qt MediaPlayer 从内存中播放音频

rust - 如何使用 winrt-rs 创建 MessageDialog?