Implementation of a ImmutableCell<'a, T>

Hey I've recently found myself in a situation where I basically want a &'a T as the type of a struct field, but don't want to deal with passing in a reference when constructing the struct, basically owning the data but only ever getting immutable references to it.

So I've decided to try to implement the following to help with that:

struct ImmutableCell<'a, T>
where
    T: 'a,
{
    data: UnsafeCell<T>,
    _p: PhantomData<&'a T>,
}

impl<'a, T> ImmutableCell<'a, T>
where
    T: 'a,
{
    fn new(data: T) -> Self {
        Self {
            data: UnsafeCell::new(data),
            _p: PhantomData,
        }
    }

    fn get(&self) -> &'a T {
        unsafe { &*self.data.get() }
    }
}

In my mind this should be fully sound since there is no way to modify the data once passed into a ImmutableCell, but i am not sure about that. Would love some comments :slight_smile:

This is unsound because a ImmutableCell<'a, T> may be dropped before the lifetime 'a ends, so get() will return a reference that eventually dangles (points to deallocated, or at least deinitialized, memory).

4 Likes

thanks, that makes sense

Here's an easy abuse.

2 Likes

In general, if you think that you found a "limitation" in lifetimes and you circumvent it using unsafe, it's a 99.9999% chance that you are doing wrong and what you have written is trivially (in the best case) or subtly (in a much worse case) unsound.

2 Likes

Based on your description it seems you want just:

struct ImmutableCell<T>(T);

impl<T> ImmutableCell<T>
{
    fn new(data: T) -> Self {
        Self(data)
    }

    fn get(&self) -> &T {
        &self.0
    }
}
5 Likes

Note that if T itself contains a Cell or similar, it still won't truly be immutable.

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.