最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Is moving a value guarantee it's copy? - Stack Overflow

programmeradmin3浏览0评论

Consider the code:

use std::mem::MaybeUninit;

struct Foo {
    buffer: MaybeUninit<[u8; 32]>,
}

fn call_device(_p: *mut [u8; 32]) {
    //....
}

fn do_magic(mut f: Foo) -> Foo {
    // Pass f.buffer to hardware device modifying it's content
    // ...
    call_device(f.buffer.as_mut_ptr());
    f // Return it back, moving
}

fn main() {
    let foo = Foo {
        buffer: MaybeUninit::uninit(),
    };
    
    let new_foo = do_magic(foo); // <--- foo moved 
    
    let result = unsafe { new_foo.buffer.assume_init() };
    
    println!("{:?}", result)
}

Here, as commented, the do_magic() function is passing the buffer to some device which is populating it with some values. But apparently it is not visible to Rust. Will it still preserve the value between the moves of Foo and the result will contain the value written by the device, or there is a chance that it will get optimized? If there is, how to prevent it (other than prevent moving by using pinned references and such)?

Consider the code:

use std::mem::MaybeUninit;

struct Foo {
    buffer: MaybeUninit<[u8; 32]>,
}

fn call_device(_p: *mut [u8; 32]) {
    //....
}

fn do_magic(mut f: Foo) -> Foo {
    // Pass f.buffer to hardware device modifying it's content
    // ...
    call_device(f.buffer.as_mut_ptr());
    f // Return it back, moving
}

fn main() {
    let foo = Foo {
        buffer: MaybeUninit::uninit(),
    };
    
    let new_foo = do_magic(foo); // <--- foo moved 
    
    let result = unsafe { new_foo.buffer.assume_init() };
    
    println!("{:?}", result)
}

Here, as commented, the do_magic() function is passing the buffer to some device which is populating it with some values. But apparently it is not visible to Rust. Will it still preserve the value between the moves of Foo and the result will contain the value written by the device, or there is a chance that it will get optimized? If there is, how to prevent it (other than prevent moving by using pinned references and such)?

Share Improve this question edited Mar 19 at 22:50 Eugene Sh. asked Mar 19 at 22:30 Eugene Sh.Eugene Sh. 18.5k8 gold badges44 silver badges68 bronze badges 10
  • If you pass the address of f, it cannot be optimized. Unless you pass it by shared reference, in which case the compiler may assume it is not mutated. – Chayim Friedman Commented Mar 19 at 22:32
  • 1 IOW: the move is not relevant here. The move just copies what was there, but what was there was changed. – Chayim Friedman Commented Mar 19 at 22:33
  • "But apparently it is not visible to Rust" - I think Chayim has provided a hint, nothing you've shown indicates that you're trying to mutate f - if you didn't get your pointer to-be-written from as_mut_ptr (or similar), then the compiler may assume no writes occurred. – kmdreko Commented Mar 19 at 22:43
  • @ChayimFriedman I changed the code a bit to make it clearer how the buffer is passed (via a mut pointer). When you say "The move just copies what was there, but what was there was changed" - you mean the copy will happen always when moving and the result in this case will get the expected value? – Eugene Sh. Commented Mar 19 at 22:45
  • @kmdreko Yeah, I modified the code to address this (I think). – Eugene Sh. Commented Mar 19 at 22:45
 |  Show 5 more comments

1 Answer 1

Reset to default 0

Yes, this code is sound as long as call_device() does properly initialize the array, for example:

fn call_device(p: *mut [u8; 32]) {
    for i in 0..32 {
        unsafe { p.cast::<u8>().add(i).write(42) };
    }
}

Running the whole thing through the Miri interpreter reveals no issues. You can try it here (click Tools -> Miri).

However, in Rust it would be much more idiomatic for do_magic() to accept a &mut Foo, so you could use the function even if you weren't the owner of the Foo. It makes the code much simpler as well.

fn do_magic(f: &mut Foo) { // no need to worry about returning anything
    call_device(f.buffer.as_mut_ptr());
}
发布评论

评论列表(0)

  1. 暂无评论