How can I reuse a box that I have moved the value out of?

后端 未结 3 798
北海茫月
北海茫月 2021-01-11 18:26

I have some non-copyable type and a function that consumes and (maybe) produces it:

type Foo = Vec;

fn quux(_: Foo) -> Option {
             


        
相关标签:
3条回答
  • 2021-01-11 19:05

    We can write a function that temporarily moves out contents of the NotBox and puts something back in before returning it

    That's because you can partially move out from the struct that you take by value. It behaves as if all fields were separate variables. That is not possible though if the struct implements Drop, because drop needs the whole struct to be valid, always (in case of panic).

    As for providing workaround, you haven't provided enough information – especially, why baz needs to take Box as an argument and why quux can't? Which functions are yours and which are part of an API you can't change? What is the real type of Foo? Is it big?

    The best workaround would be not to use Box at all.

    0 讨论(0)
  • 2021-01-11 19:10

    So, moving out of a Box is a special case... now what?

    The std::mem module presents a number of safe functions to move values around, without poking holes (!) into the memory safety of Rust. Of interest here are swap and replace:

    pub fn replace<T>(dest: &mut T, src: T) -> T
    

    Which we can use like so:

    fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
        let foo = std::mem::replace(&mut *abox, Foo::default());
    
        match quux(foo) {
            Some(new_foo) => {
                *abox = new_foo;
                Some(abox)
            }
            None => None
        }
    }
    

    It also helps in the map case, because it does not borrow the Box:

    fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> {
        let foo = std::mem::replace(&mut *abox, Foo::default());
    
        quux(foo).map(|new_foo| { *abox = new_foo; abox })
    }
    
    0 讨论(0)
  • 2021-01-11 19:10

    Moving out of boxes is special-cased in the compiler. You can move something out of them, but you can't move something back in, because the act of moving out also deallocates. You can do something silly with std::ptr::write, std::ptr::read, and std::ptr::replace, but it's hard to get it right, because something valid should be inside a Box when it is dropped. I would recommend just accepting the allocation, or switching to a Box<Option<Foo>> instead.

    0 讨论(0)
提交回复
热议问题