Rust и C++ FFI: оркестровка деструкторов/удаление полей структурыC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Rust и C++ FFI: оркестровка деструкторов/удаление полей структуры

Сообщение Anonymous »

Поскольку некоторый код FFI взаимодействует с C++, мне нужен точный ручной контроль над тем, когда метод типов Drop::drop() вызывается относительно. те из полей.
Если точнее:
  • Когда структура C++ уничтожается, вызывается деструктор (), а затем поля уничтожаются в обратном порядке объявления.
  • Когда структура Rust удаляется, вызывается Drop::drop(), а затем поля удаляются в порядке объявления.
Если мы игнорируем различный порядок удаления полей, механизмы очень похожи, поэтому T::~T() в C++ играет роль Drop::drop() в Rust.
Предположим, у меня есть структура в Rust:

Код: Выделить всё

#[repr(C)]
pub struct MyStruct {
field: AnotherStruct
}

#[repr(C)]
pub struct AnotherStruct {
something: *mut i32
}

impl Drop for MyStruct {
// ...
}

impl Drop for AnotherStruct {
// ...
}
На стороне C++ я могу объявить структуры следующим образом:

Код: Выделить всё

struct AnotherStruct {
int32_t *something;

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

struct MyStruct {
AnotherStruct field;

~MyStruct() {
// what to put here
}
};
Теперь, будучи #[repr(C)], я могу передавать структуры по значению во внешнюю функцию "C":
Rust:

Код: Выделить всё

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

Код: Выделить всё

extern "C" {
void test(MyStruct object) {
// use `object`...
}
}
Теперь проблема в том, что во избежание утечек и т. д. мне нужно заполнить деструкторы двух приведенных выше структур C++.
В идеале из C++ я должен:
  • вызвать MyStruct::drop() в MyStruct::~MyStruct()
  • позволим C++ вызвать деструктор поля
  • вызвать AnotherStruct::drop() в AnotherStruct::~AnotherStruct()
  • позволить C++ вызвать деструктор ptr (что является пустой операцией).
Обратите внимание, что на шаге 1 я не могу использовать std::ptr::drop_in_place(), потому что полное удаление MyStruct также приведет к удалению его поля, но позже C++ снова вызовет деструктор поля.
Поэтому мне нужно намеренно игнорировать выполнение drop_in_place(). Однако, похоже, в Rust невозможно вызвать Drop::drop() без связующего звена.
Обратите внимание, что проблема возникает только потому, что я пытаюсь переместить структуру во внешнюю функцию "C". Если я передаю что-то по ссылке, я могу свободно использовать std::ptr::drop_in_place(), потому что деструкторы C++ вообще не будут работать. Но это именно то, что я хочу/нужно сделать.
Некоторые очевидные решения для меня неприемлемы, в частности:
  • Я не могу изменить API экспортируемых структур Rust, поэтому я не могу изменить поле: AnotherStruct для поля: ManuallyDrop
  • На На стороне C++ я могу избежать запуска деструкторов поля, обернув поле в объединение, например:

    Код: Выделить всё

    struct MyStruct {

    Код: Выделить всё

       union { AnotherStruct field; } field_u;
    но тогда мне нужно будет использовать поле как object.field_u.field вместо object.field, и мне нужно этого избегать.
Итак, есть ли какой-нибудь выход из этой проблемы?>

Подробнее здесь: https://stackoverflow.com/questions/798 ... uct-fields
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»