Are raw pointers to temporaries ok in Rust?

2019-06-15 14:50发布

问题:

I have a function like this:

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

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

Where Layout is a copyable type that can be converted .into() a RawLayout.

I want to make sure I understand what is happening as it is unsafe. As I understand it, layout.into() creates a temporary RawLayout, then & takes a reference to it, and as *const _ converts it to a raw pointer (*const RawLayout). Then the foo() function is called and returns, and finally the temporary RawLayout is dropped.

Is that correct? Or is there some tricky reason why I shouldn't do this?

回答1:

You are right. In this case, foo is called first and RawLayout is dropped afterwards. This is explained in The Rust Reference (follow the link to see concrete examples of how this works out in practice):

The lifetime of temporary values is typically the innermost enclosing statement

However, I would rather follow Shepmaster's advice. Explicitly introducing a local variable would help the reader of the code concentrate in more important things, like ensuring that the unsafe code is correct (instead of having to figure out the exact semantics of temporary variables).

How to check this

You can use the code below to check this behavior:

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);    
}

The output is:

foo called
Dropping RawLayout


标签: rust