В Rust нормальны исходные ссылки на временные файлы?

У меня есть такая функция:

extern {
    fn foo(layout: *const RawLayout) -> libc::uint8_t;
}

fn bar(layout: Layout) -> bool {
    unsafe {
        foo(&layout.into() as *const _) != 0
    }
}

куда Layout это копируемый тип, который может быть преобразован .into() RawLayout,

Я хочу убедиться, что я понимаю, что происходит, поскольку это небезопасно. Как я понимаю, layout.into() создает временный RawLayout, затем & берет ссылку на это, и as *const _ преобразует его в необработанный указатель (*const RawLayout). Тогда foo() Функция вызывается и возвращает, и, наконец, временный RawLayout упал

Это верно? Или есть какая-то хитрая причина, почему я не должен этого делать?

1 ответ

Решение

Вы правы. В этом случае, foo называется первым и RawLayout упал впоследствии. Это объясняется в The Rust Reference (перейдите по ссылке, чтобы увидеть конкретные примеры того, как это работает на практике):

Время жизни временных значений, как правило, является самым внутренним приложением

Однако я бы предпочел последовать совету Шепмастера. Явное введение локальной переменной поможет читателю кода сконцентрироваться на более важных вещах, таких как обеспечение правильности небезопасного кода (вместо выяснения точной семантики временных переменных).

Как это проверить

Вы можете использовать код ниже, чтобы проверить это поведение:

struct Layout;
struct RawLayout;

impl Into<RawLayout> for Layout {
    fn into(self) -> RawLayout {
        RawLayout
    }
}

impl Drop for RawLayout {
    fn drop(&mut self) {
        println!("Dropping RawLayout");
    }
}

unsafe fn foo(layout: *const RawLayout) -> u8 {
    println!("foo called");
    1
}

fn bar(layout: Layout) -> bool {
    unsafe {
        foo(&layout.into() as *const _) != 0
    }
}

fn main() {
    bar(Layout);    
}

Выход:

foo called
Dropping RawLayout
Другие вопросы по тегам