1

I have this container:

use std::ptr::NonNull;

struct Container {
    data: NonNull<u8>,
}

impl Container {
    fn new() -> Container {
        todo!()
    }
    fn borrow_some_heap_data<'a>(&'a self) -> &'a u8 {
        todo!()
    }
    fn borrow_some_heap_data_mut<'a>(&'a mut self) -> &'a mut u8 {
        todo!()
    }
}

impl Drop for Container {
    fn drop(&mut self) {
        todo!()
    }
}

fn main() {
    let container = Container::new();
    let data = container.borrow_some_heap_data(); // or mut

    {
        let container = container; // move

        // This is safe because the move is a memcpy and the heap data doesn't change.
        println!("{}", *data);
    }

    // This is not safe because the container has been dropped
    // println!("{}", *data);
}
error[E0505]: cannot move out of `container` because it is borrowed
  --> src/main.rs:30:25
   |
27 |     let data = container.borrow_some_heap_data(); // or mut
   |                --------- borrow of `container` occurs here
...
30 |         let container = container; // move
   |                         ^^^^^^^^^ move out of `container` occurs here
...
33 |         println!("{}", *data);
   |                        ----- borrow later used here

Moving the container is safe even if there are references. Dropping it, however, is not safe. Is there any way to express this in Rust, to allow moves but not drops?

data is never deallocated until the struct is dropped.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
me'
  • 494
  • 3
  • 14
  • `std::mem::drop` works by moving the value, too. It's impossible to distinguish `let container = container` and `drop(container)`, since both are moves. – Cerberus Nov 15 '20 at 05:35
  • I suppose so, but `std::mem::drop` moves and drops when it goes out of scope. If I dropped `container` by shadowing it in a new scope, reading `data`, then exiting the scope, the second `println` would still be unsafe. – me' Nov 15 '20 at 05:44
  • 1
    Heads up, don't put EDIT markers into your question. It's better to just edit it without drawing attention to the updates. – John Kugelman Nov 15 '20 at 05:55

1 Answers1

1

No, there is no way of doing this in safe Rust; the compiler is not intelligent enough / there's no syntax to distinguish the container's lifetime from the lifetimes of the elements.

From Why can't I store a value and a reference to that value in the same struct?:

There is a special case where the lifetime tracking is overzealous: when you have something placed on the heap. This occurs when you use a Box<T>, for example. In this case, the structure that is moved contains a pointer into the heap. The pointed-at value will remain stable, but the address of the pointer itself will move. In practice, this doesn't matter, as you always follow the pointer.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366