Lifetime error with iterator of mutable smart pointers

I'm implementing a 2D grid type with smart pointers, both non-mutable and mutable, and I want to be able to iterate over the smart pointers to each cell of the grid, both non-mutably and mutably. Implementing an iterator over non-mutable smart pointers went fine, but when I tried to do the equivalent for mutable smart pointers, I got a lifetime error. The only way I can see to solve this error would be to add the 'a lifetime to the receiver in next(), but that's incompatible with the trait definition.

Very minimal MVCE:

// Bounds-checking omitted for brevity

struct MyVec<T>(Vec<T>);

impl<T> MyVec<T> {
    fn get_cell_mut(&mut self, i: usize) -> CellMut<'_, T> {
        CellMut::new(self, i)
    }
    
    fn iter_cell_muts(&mut self) -> IterCellMuts<'_, T> {
        IterCellMuts::new(self)
    }
}

struct CellMut<'a, T> {
    vec: &'a mut MyVec<T>,
    i: usize,
}

impl<'a, T> CellMut<'a, T> {
    fn new(vec: &'a mut MyVec<T>, i: usize) -> Self {
        CellMut { vec, i }
    }

    fn get(&mut self) -> &mut T {
        &mut self.vec.0[self.i]
    }
}

struct IterCellMuts<'a, T> {
    vec: &'a mut MyVec<T>,
    i: usize,
}

impl<'a, T> IterCellMuts<'a, T> {
    fn new(vec: &'a mut MyVec<T>) -> Self {
        IterCellMuts {vec, i: 0}
    }
}

impl<'a, T> Iterator for IterCellMuts<'a, T> {
    type Item = CellMut<'a, T>;
    
    fn next(&mut self) -> Option<CellMut<'a, T>> {
        if self.i < self.vec.0.len() {
            let r = Some(self.vec.get_cell_mut(self.i));
            self.i += 1;
            r
        } else {
            None
        }
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: lifetime may not live long enough
  --> src/lib.rs:48:13
   |
41 | impl<'a, T> Iterator for IterCellMuts<'a, T> {
   |      -- lifetime `'a` defined here
...
44 |     fn next(&mut self) -> Option<CellMut<'a, T>> {
   |             - let's call the lifetime of this reference `'1`
...
48 |             r
   |             ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`

error: could not compile `playground` due to previous error

As written, your code would allow a caller to create multiple simultaneous &mut MyVec<T> references by collecting the iterator (because each cell type contains a copy of the reference). That's definitely unsound.

The standard library avoids this by only returning mutable references to each element, and none of the references overlap so there's no problem there.

1 Like

Right, so I can't have multiple CellMuts at once. Guess I'll need another approach, then. Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.