Genauer gesagt:
- Wenn eine C++-Struktur zerstört wird, wird der Destruktor aufgerufen () und dann werden die Felder in umgekehrter Deklarationsreihenfolge zerstört.
Code: Select all
T::~T() - Wenn eine Rust-Struktur gelöscht wird, wird Drop::drop() aufgerufen und dann werden die Felder in Deklarationsreihenfolge gelöscht.
Angenommen, ich habe eine Struktur in Rust:
Code: Select all
#[repr(C)]
pub struct MyStruct {
field: AnotherStruct
}
#[repr(C)]
pub struct AnotherStruct {
something: *mut i32
}
impl Drop for MyStruct {
// ...
}
impl Drop for AnotherStruct {
// ...
}
Code: Select all
struct AnotherStruct {
int32_t *something;
~AnotherStruct() {
// what to put here
}
};
struct MyStruct {
AnotherStruct field;
~MyStruct() {
// what to put here
}
};
Rust:
Code: Select all
unsafe extern "C" {
pub fn test(object: MyStruct);
}
Code: Select all
extern "C" {
void test(MyStruct object) {
// use `object`...
}
}
Idealerweise sollte ich aus C++:
- MyStruct::drop() aufrufen in MyStruct::~MyStruct() aufrufen
- C++ aufrufen lassen den Destruktor von field
- AnotherStruct::drop() in AnotherStruct::~AnotherStruct() aufrufen
- Lassen Sie C++ den Destruktor von ptr aufrufen (was ein No-Op ist).
Ich muss also absichtlich die Ausführung des Drop-Glue auf der Rust-Seite ignorieren. Es scheint jedoch, dass es in Rust keine Möglichkeit gibt, Drop::drop() ohne den Kleber aufzurufen.
Beachten Sie, dass das Problem nur auftritt, weil ich versuche, eine Struktur in eine externe „C“-Funktion zu verschieben. Wenn ich Dinge als Referenz übergebe, kann ich std::ptr::drop_in_place() frei verwenden, da C++-Destruktoren überhaupt nicht ausgeführt werden. Aber genau das möchte/muss ich tun.
Einige scheinbare Lösungen sind für mich nicht realisierbar, insbesondere:
- Ich kann die API der Rust-Strukturen, die ich exportiere, nicht ändern, also kann ich das Feld: AnotherStruct für das Feld: ManuallyDrop
- nicht ändern. Auf der C++-Seite I kann die Ausführung der Destruktoren des Felds verhindern, indem das Feld in eine Union eingeschlossen wird, wie zum Beispiel:
Code: Select all
struct MyStruct {Code: Select all
union { AnotherStruct field; } field_u;aber dann müsste ich das Feld als object.field_u.field anstelle von object.field verwenden und das muss ich vermeiden.Code: Select all
};
Mobile version