If we look at the following code (playground link):
use std::cell::RefCell;
use std::rc::Rc;
struct Person {
name: String,
parent: Option<Rc<RefCell<Person>>>,
child: Option<Rc<RefCell<Person>>>,
}
impl Drop for Person {
fn drop(&mut self) {
println!("dropping {}", &self.name);
}
}
pub fn main() {
let anakin = Rc::new(RefCell::new(Person {
parent: None,
child: None,
name: "anakin".to_owned(),
}));
let luke = Rc::new(RefCell::new(Person {
parent: None,
child: None,
name: "luke".to_owned(),
}));
luke.borrow_mut().parent = Some(anakin.clone());
anakin.borrow_mut().child = Some(luke.clone());
println!("anakin {}", Rc::strong_count(&anakin));
println!("luke {}", Rc::strong_count(&luke));
}
When the code runs, the message from the drop implementation is not printed, because this code is supposed to leak memory.
When the code finishes the count for both luke and anakin is supposed to end up at 1 rather than 0 (which is when the managed heap data would be cleaned up).
Why does the count not end up being 0? I would have thought the following sequence would happen:
we start with two data locations in heap, one pointed to by luke and anakin.child, the other pointed to by anakin and luke.parent. The object luke owns luke.parent. The object anakin owns anakin.child
luke goes out of scope, which means its members which it owns are also dropped. So luke and luke.parent drop. Both are Rcs, so the ref count for both the memory locations therefore goes down to 1
anakin is dropped, causing the Rc object anakin and anakin.child to drop, which causes ref count for both memory locations to go down to 0.
This is where the heap data should be cleaned up? Are the members of an object not dropped when it is dropped?
When I remove or comment the lines connecting luke and anakin via borrow_mut, the drop happens as expected and the messages are correctly printed.