Rust und C++ FFI: Destruktoren/Drops von Strukturfeldern orchestrierenC++

Programme in C++. Entwicklerforum
Anonymous
 Rust und C++ FFI: Destruktoren/Drops von Strukturfeldern orchestrieren

Post by Anonymous »

Da FFI-Code mit C++ interagiert, benötige ich eine präzise manuelle Kontrolle darüber, wann die Drop::drop()-Methode von Typen aufgerufen wird. die von Feldern.
Genauer gesagt:
  • Wenn eine C++-Struktur zerstört wird, wird der Destruktor aufgerufen (

    Code: Select all

    T::~T()
    ) und dann werden die Felder in umgekehrter Deklarationsreihenfolge zerstört.
  • Wenn eine Rust-Struktur gelöscht wird, wird Drop::drop() aufgerufen und dann werden die Felder in Deklarationsreihenfolge gelöscht.
Wenn wir die unterschiedliche Ablagereihenfolge der Felder ignorieren, sind die Mechanismen ziemlich ähnlich T::~T() in C++ hat die Rolle von Drop::drop() in Rust.
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 {
// ...
}
Auf der C++-Seite kann ich die Strukturen wie folgt deklarieren:

Code: Select all

struct AnotherStruct {
int32_t *something;

~AnotherStruct() {
// what to put here
}
};

struct MyStruct {
AnotherStruct field;

~MyStruct() {
// what to put here
}
};
Da ich nun #[repr(C)] bin, kann ich die Strukturen als Wert an eine externe „C“-Funktion übergeben:
Rust:

Code: Select all

unsafe extern "C" {
pub fn test(object: MyStruct);
}
C++:

Code: Select all

extern "C" {
void test(MyStruct object) {
// use `object`...
}
}
Das Problem besteht nun jedoch darin, dass ich zur Vermeidung von Lecks usw. die Destruktoren der beiden oben genannten C++-Strukturen füllen muss.
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).
Beachten Sie, dass ich in Schritt 1 nicht verwenden kann std::ptr::drop_in_place(), weil das vollständige Löschen von MyStruct auch sein Feld löschen würde, aber später würde C++ den Destruktor von field erneut aufrufen.
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;

    Code: Select all

    };
    aber dann müsste ich das Feld als object.field_u.field anstelle von object.field verwenden und das muss ich vermeiden.
Gibt es also einen Ausweg aus diesem Problem?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post