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


这段代码工作正常,但每晚都会在Rust上发出编译器警告(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     }

什么是正确的方法来确保这些 DbaxCells正确清理,没有给出警告?


7146
2018-06-09 20:16


起源



答案:


我认为你正在混淆两个概念。结构应该是 repr(C) 如果你希望结构的布局 直接对应 作为C编译器将结构布局。也就是说,它具有相同的内存 representation。

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

更多地解释错误......

实现Drop会向类型添加隐藏状态,可能与之冲突 #[repr(C)]

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

来自@bluss

低级程序员,不要担心: 未来的锈 将完全删除此删除标记。

使用 repr(C) 在FFI中传递结构,并使用 Drop 如果你需要,可以使用“常规Rust”结构。如果你需要两者,嵌入 repr(C) 常规结构中的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
}

9
2018-06-09 20:26



低级程序员,不要担心:未来的生锈将完全消除这种下降标志。 - bluss
@bluss:你有时间表吗?这也让我烦恼...... - Matthieu M.
跟踪问题。最近取得了进展,而不仅仅是在那里出现。我希望这将是今年的某个时候。 - bluss
也许这个答案应该解释一下?使用 repr(C) 在ffi中传递结构,并使用 Drop 如果你需要,可以使用“常规Rust”结构。如果你需要两者,嵌入 repr(C) 常规生锈结构中的struct。 - bluss
@bluss介意给我的上次更新看看和一些反馈? - Shepmaster


答案:


我认为你正在混淆两个概念。结构应该是 repr(C) 如果你希望结构的布局 直接对应 作为C编译器将结构布局。也就是说,它具有相同的内存 representation。

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

更多地解释错误......

实现Drop会向类型添加隐藏状态,可能与之冲突 #[repr(C)]

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

来自@bluss

低级程序员,不要担心: 未来的锈 将完全删除此删除标记。

使用 repr(C) 在FFI中传递结构,并使用 Drop 如果你需要,可以使用“常规Rust”结构。如果你需要两者,嵌入 repr(C) 常规结构中的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
}

9
2018-06-09 20:26



低级程序员,不要担心:未来的生锈将完全消除这种下降标志。 - bluss
@bluss:你有时间表吗?这也让我烦恼...... - Matthieu M.
跟踪问题。最近取得了进展,而不仅仅是在那里出现。我希望这将是今年的某个时候。 - bluss
也许这个答案应该解释一下?使用 repr(C) 在ffi中传递结构,并使用 Drop 如果你需要,可以使用“常规Rust”结构。如果你需要两者,嵌入 repr(C) 常规生锈结构中的struct。 - bluss
@bluss介意给我的上次更新看看和一些反馈? - Shepmaster