Pytanie Poprawiono idiom do uwalniania struktur repr (C) za pomocą cechy Drop


Ten kod działa poprawnie, ale daje ostrzeżenie kompilatora na 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);
        }
    }
}

Łączy się z biblioteką C i poprawnie tworzy / usuwa obiekty komórki. 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, aby to zapewnić DbaxCells są prawidłowo czyszczone i nie ma ostrzeżenia?


11
2018-06-09 20:16


pochodzenie




Odpowiedzi:


Myślę, że łączysz dwie koncepcje. Powinna to być struktura repr(C) jeśli chcesz mieć układ struktury bezpośrednio odpowiadają do układu struktury jako kompilatora języka C by to ułożył. Oznacza to, że ma tę samą pamięć wewnętrzną representation.

Jednak ty nie rób tego potrzebujesz, jeśli tylko trzymasz surowy wskaźnik i nie zamierzasz przekazać struktury trzymającej z powrotem do C. Krótkie rozwiązanie w tym przypadku to "usuń repr(C)".

Aby wyjaśnić nieco więcej o błędzie ...

implementacja Drop dodaje ukryty stan do typów, z którymi może kolidować #[repr(C)]

Było to omówione w wydanie 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).

Tak jak żłobiony z @bluss:

Programiści niskiego poziomu, nie martw się: przyszłość Rust całkowicie usunie flagę kropli.

I

Posługiwać się repr(C) przekazywać struktury w FFI i używać Drop na "regularnych Rust" struktur, jeśli musisz. Jeśli potrzebujesz obu, załóż plik repr(C) struct wewnątrz regularnej struktury.

Wyobraźmy sobie, że mamy bibliotekę, która eksponuje strukturę C z dwoma liczbami 8-bitowymi oraz metody, które pobierają i zwracają tę strukturę:

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

tuple_t tuple_increment(tuple_t position);

W takim przypadku na pewno chcesz naśladować tę strukturę i dopasować do reprezentacji C w Rust:

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

Jednakże, jeśli biblioteka zwróciła wskaźniki do struktury, i nigdy nie trzeba w nią zaglądać (struktura jest nieprzezroczysty) wtedy nie musisz się martwić repr(C):

void tuple_increment(tuple_t *position);

Następnie możesz po prostu użyć tego wskaźnika i zaimplementować 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



Programiści niskiego poziomu, nie martwcie się: przyszła rdza całkowicie usunie flagę kropli. - bluss
@bluss: Czy masz jakąkolwiek oś czasu? To też mnie denerwowało ... - Matthieu M.
Problem z śledzeniem. Jest najnowszy postęp, więcej niż się tam pojawia. Mam nadzieję, że będzie to w tym roku. - bluss
Może ta odpowiedź powinna wyjaśnić nieco więcej? Posługiwać się repr(C) przekazać structs w ffi i użyć Drop na "regularnych Rust" struktur, jeśli musisz. Jeśli potrzebujesz obu, załóż plik repr(C) Wewnątrz regularnej struktury rdzy. - bluss
@blus umysł podając moją ostatnią aktualizację spojrzenie-zobacz i kilka opinii? - Shepmaster