why reference counting exist..when reference counting is needed or efficient to use ?
Reference counting is useful when you need shared ownership of something and it's impossible to know how long the thing will be alive for at compile time.
For example, say I want to share a flag between the main thread and a background thread.
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
let cancel_requested = Arc::new(AtomicBool::new(false));
// Get a second reference to the flag and pass it to a background thread
let cancel_requested_2 = Arc::clone(&flag);
std::thread::spawn(move || {
// Keep doing some work until the flag is set
while !cancel_requested_2.load(Ordering::Relaxed) {
do_some_work_in_the_background();
}
});
println!("Press enter to stop doing work.");
let mut buffer = String::new();
std::io::stdin().read_line(&mut buffer)?;
// the user has hit enter so our background loop should finish
cancel_requested.store(true, Ordering::Relaxed);
It's a bit of a toy example, but because a background thread can theoretically outlive the main thread, there's no way to know how long our cancel_requested
flag will live at compile time. That means you can't (in general) use lifetimes to avoid use-after-free issues.
Here's a simple example in rusty-looking pseudo-code.
// value is some kinda value we might want to use
let value = NodeValue::new();
// list has a reference to value
list.add(&value);
// tree also has a reference to value
tree.add(&value);
// pre_filter can mutate the list,
// the list may or may not contain ref to value afterward
list.pre_filter();
// Now we mutate tree too!
tree.drop_leaf();
// More Code goes here
// Can't do this! list or tree might still have a ref to value!
drop(value);
In the example above since we can't know whether the references to value
have been dropped, we can't drop value
. Value
needs to continue wasting memory until both tree
and list
have been dropped even if neither of them actually has the reference anymore. That could be the entire time the program is running.
You can use reference counting via Rc
to solve this problem. Rc
will let value
be dropped the moment both tree
and list
have dropped their references.
// value is some kinda value we might want to use
let value = Rc::new(NodeValue::new());
// list has the value, there are now 2 references
list.add(value.clone());
// tree also the value, it takes the original reference
// so there are still 2 references.
tree.add(value);
// pre_filter can mutate the list,
// the list may or may not contain ref to value afterward
list.pre_filter();
// Now we mutate tree too!
tree.drop_leaf();
// More Code goes here
In the example above, by the time you get to "More Code"
-
value
may be dropped (not in eithertree
orlist
) -
value
may exist only inlist
-
value
may exist only intree
-
value
may exist in bothtree
andlist
Rc
is managing this for us at runtime since we really can't know at compile-time which of the 4 scenarios above will be true.
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.