0

(Experienced C, C++, Python programmer. New to rust, still trying to wrap my head around lifetimes, borrows, moves, and the ways references are different from C pointers)

I'm trying to represent a list of locations, where each location has a size and offset:

struct FreeLoc {
    size: u64,
    offset: u64
}

These live in and are owned by a Vec in another struct. For lookup performance, I want to maintain this list in two separate orderings -- one sorted by size, and the other by offset. I have the owning Vec (free), and two Vec<&FreeLoc> to store references to the objects in the owning Vec, sorted appropriately:

struct FreeList<'a> {
    free: Vec<FreeLoc>,
    by_size: Vec<&'a FreeLoc>,
    by_offset: Vec<&'a FreeLoc>
}

impl<'a> FreeList<'a> {
    pub fn new(size: u64) -> Self {
        let mut s = Self {
            free: vec![ FreeLoc { size: size, offset: 0 }],
            by_size: Vec::new(),
            by_offset: Vec::new()
        };
        s.by_size.push(&s.free[0]);
        s.by_offset.push(&s.free[0]);
        s
    }
}

I get the following build errors:

error[E0515]: cannot return value referencing local data `s.free`
  --> src/freelist/freelist.rs:31:9
   |
28 |         s.by_size.push(&s.free[0]);
   |                         ------ `s.free` is borrowed here
...
31 |         s
   |         ^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `s` because it is borrowed
  --> src/freelist/freelist.rs:31:9
   |
21 | impl<'a> VecFreeList<'a> {
   |      -- lifetime `'a` defined here
...
28 |         s.by_size.push(&s.free[0]);
   |                         ------ borrow of `s.free` occurs here
...
31 |         s
   |         ^
   |         |
   |         move out of `s` occurs here
   |         returning this value requires that `s.free` is borrowed for `'a`

error[E0515]: cannot return value referencing local data `s.free`
  --> src/freelist/freelist.rs:31:9
   |
29 |         s.by_offset.push(&s.free[0]);
   |                           ------ `s.free` is borrowed here
30 |
31 |         s
   |         ^ returns a value referencing data owned by the current function

There are several questions here:

  1. Is the error with line 31 a side effect of s being allocated on the stack? When ::new returns, the physical memory location of s moves, and therefore the references in s.by_size and s.by_offset are no longer valid?
31 |         s
   |         ^ returns a value referencing data owned by the current function
  1. What is the "right" way to get around this problem? Allocate the FreeLocs on the heap using Box? And therefore the FreeList turns into:
struct FreeList<'a> {
    free: Vec<Box<FreeLoc>>,
    by_size: Vec<&'a Box<FreeLoc>>,
    by_offset: Vec<&'a Box<FreeLoc>>
}
  1. Is this really the right way to handle heap allocation in rust? Seems super clunky.
scubabuddha
  • 795
  • 5
  • 9

0 Answers0