I am looking for a smart pointer similar to Arc/Rc except that it does not allow shared ownership.
I want to have as many rc::Weak references as I need, but I only want one strong reference, a.k.a owner. And I want to enforce that with the type system.
Arc/Rc can be cloned, and they can be owned at several places.
Rolling up my own smart pointer would be an option, but I believe such data structure should already exist, even if outside the standard library.
I am looking for a data structure providing this kind of interface:
impl MySmartPointer<T> {
fn new(object: T) -> Self;
fn weak_ref(&self) -> WeakRef<T>;
fn get_mut(&mut self) -> &mut T;
}
impl WeakRef<T> {
/// If the strong pointer `MySmartPointer` has been dropped,
/// return `None`. Else return Some(&T);
fn get(&self) -> Option<&T>;
}
Let's assume it exists with types Strong<T> and Weak<T>. How do you use Weak<T>? You need some kind of fallible "upgrade" step, so what does Weak<T> upgrade to? It can't be to a plain reference (as you've stated), because Strong<T> needs to know whether or not any "upgraded" Weak<T>s exist. If it didn't, it could deallocate its storage whilst the value is still being accessed.
So Weak<T> must upgrade to some kind of SemiWeak<T> which keeps the underlying allocation alive... which is exactly what shared ownership is.
What if you somehow guaranteed that Strong<T> couldn't be deallocated before all Weak<T>s go away? Congratulations, you've just re-invented T and &T: you could literally just use those instead.
Alright, so what if you made it so that Weak<T> upgrades into a SemiWeak<'a, T> that is tied to the lifetime of the Weak<T> so that it can't outlive it, and can only be a temporary? All you're really doing in that case is hiding the fact that you've got shared ownership. Under the hood, SemiWeak would still need to guarantee the underlying Strong can't go away. You could trivially build such a type from Rc<T> in perhaps ten minutes. This would effectively give you a type that is exactly like Rc<T>, with the same performance and memory cost, but less useful.
In addition, that get_mut method can't exist. There's no way to prevent SemiWeak<T>s from existing. Unless you use borrowing but, again, that's just using T and &T.
So, no, I don't think this exists, nor do I believe it can in the form you've described.
As a final aside, just having Weak<T> at all is a form of shared ownership, because those Weak<T>s need to point to something. In the case of Rc<T>, the weak counter is stored right alongside the strong counter, so whilst the value can be destroyed, the allocation itself sticks around. You could split the two, but now you're paying for two allocations and double indirection (probably leading to more cache misses).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With