2015-06-09 9 views
11

Ten kod działa dobrze, ale daje ostrzeżenie kompilatora na Rust nightly (1,2)Prawidłowe idiom za uwolnienie repr (C) konstrukcjom użyciu Opadowej cechę

#[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); 
     } 
    } 
} 

To linki do biblioteki C i tworzy/usuwanie obiektów komórkowych poprawnie . Jednak daje ostrzeżenie

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  } 

Jaki jest właściwy sposób to zrobić, aby upewnić się, że te DbaxCell s są czyszczone prawidłowo i nie jest ostrzeżenie?

Odpowiedz

9

Myślę, że łączysz dwie koncepcje. Struktura powinna być repr(C), jeśli chcesz, aby układ struktury do bezpośrednio odpowiadał na układ struktury, ponieważ kompilator języka C mógłby ją ułożyć. Oznacza to, że ma tę samą inskrypcję w pamięci.

Jednak ty nie trzeba, że ​​jeśli tylko trzyma surowego wskaźnik, i nie zamierzamy przekazać strukturę do powstrzymując C. krótkie rozwiązaniem w tym przypadku jest „usunięcie repr(C)”.

Aby wyjaśnić nieco więcej na temat tego błędu ...

realizacji Kropla dodaje ukrytego stanu do typów, potencjalnie sprzecznych z #[repr(C)]

ten został omówiony w issue 24585. Kiedy obiekt jest upuszczany, ustawiana jest ukryta flaga ("stan"), która wskazuje, że obiekt został upuszczony, co uniemożliwia wielokrotne upuszczenie. Jednak ukryte bity oznaczają, że to, co widzisz w Rust, nie odpowiada temu, jak bajty struktury wyglądałyby w C, negując cel repr(C).

Jak cribbed from @bluss:

Niski poziom programistów, nie martw się: future Rust usunie tę flagę upuść całkowicie.

I

Zastosowanie repr(C) aby przypisać struktury w FFI i używać Drop na "normalne" Rust elemencie, jeśli trzeba. Jeśli potrzebujesz obu, wbuduj strukturę repr(C) do zwykłej struktury.

Wyobraź mieliśmy bibliotekę, która odsłania się C struct z dwóch liczb 8-bitowych i metod, które mają i powrotne, które struct:

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

tuple_t tuple_increment(tuple_t position); 

W tym przypadku, to na pewno chcą naśladować struct i mecz reprezentacji C w Rust:

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

Jednakże, jeśli biblioteka powrócił wskaźniki do struct, a ty nigdy nie trzeba grzebać w nim (struktura jest nieprzezroczysty) wtedy nie trzeba się martwić o repr(C):

void tuple_increment(tuple_t *position); 

Następnie można po prostu użyć tego wskaźnika, a także wdrożyć Kropla:

struct TuplePointer(*mut libc::c_void); 

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

Niski poziom programistów, nie martw się: przyszłość rdza usunie ta flaga kropla całkowicie. – bluss

+0

@bluss: Czy masz jakąś oś czasu? To też mnie denerwowało ... –

+0

[Problem ze śledzeniem] (https://github.com/rust-lang/rust/issues/5016). Jest najnowszy postęp, więcej niż się tam pojawia. Mam nadzieję, że będzie to w tym roku. – bluss