std::rc::Weak<T> has the following definition:
pub struct Weak<T: ?Sized> {
ptr: NonNull<RcBox<T>>,
}
In my understanding, when there's no more Rc<T> left, RcBox<T> will be freed and Weak<T>.ptr now points to a place that could potentially contain anything. So when upgrade() is called on a Weak<T>, how does it know the pointer is now invalid?
Weak<T>::upgrade has the following implementation:
pub fn upgrade(&self) -> Option<Rc<T>> {
let inner = self.inner()?;
if inner.strong() == 0 {
None
} else {
unsafe {
inner.inc_strong();
Some(Rc::from_inner(self.ptr))
}
}
}
Does this imply RcBox<T> is not really freed when there's no Rc<T> left in the wild? If so, wouldn't that leak memory?
The
RcBoxis not destroyed until there are no strong or weak pointers remaining.However, the contained
Tis dropped in place when the strong count reaches zero. This effectively destroys the containedTbut does not release the memory of theTitself. This is howWeakknows if the inner value was dropped -- if you try to upgrade aWeakto anRcwhen the strong count is zero, the operation fails and returnsNone.Once the weak count also reaches zero, the
RcBoxitself is freed. So no, there is no memory leak.Note that many types (such as
StringandVec) manage a separate heap allocation. If you have anRc<Vec<_>>, for example, when the strong count reaches zero but the weak count does not, the drop code for the innerVecruns and drops all of its owned elements as well as frees the heap allocation used to store them. The memory used by theVecitself to hold the heap pointer, length, and capacity is not freed as it is owned by theRcBox. That allocation is only freed when the strong and weak counts both reach zero.