'When to use Rc vs Box?
I have the following code which uses both Rc
and Box
; what is the difference between those? Which one is better?
use std::rc::Rc;
fn main() {
let a = Box::new(1);
let a1 = &a;
let a2 = &a;
let b = Rc::new(1);
let b1 = b.clone();
let b2 = b.clone();
println!("{} {}", a1, a2); //=> 1 1
println!("{} {}", b1, b2); //=> 1 1
}
Solution 1:[1]
Rc
provides shared ownership so by default its contents can't be mutated, while Box
provides exclusive ownership and thus mutation is allowed:
use std::rc::Rc;
fn main() {
let mut a = Box::new(1);
let mut b = Rc::new(1);
*a = 2; // works
*b = 2; // doesn't
}
In addition Rc
cannot be sent between threads, because it doesn't implement Send
.
The bottom line is they are meant for different things: if you don't need shared access, use Box
; otherwise, use Rc
(or Arc
for multi-threaded shared usage) and keep in mind you will be needing Cell
or RefCell
for internal mutability.
Solution 2:[2]
Looking at the example given in the description, I think the real question here is "when to use Rc
versus &Box
" (note the ampersand).
Both Rc
and &Box
store the underlying data on the heap, neither can be sent across threads, and both allow immutable sharing (demonstrated by the aforementioned example). However, the biggest difference is that Rc
gives you a shared (immutable) owned value while with &Box
you get a shared (immutable) reference.
In the Rc
case, the underlying data will be dropped (freed/deallocated) whenever the last owner (whether the original one or any cloned one) gets dropped – that's the idea of reference counting. In the &Box
case, however, there is only one owner: any shared references to it will become invalid immediately after the owner gets out of scope.
Said differently, contrary to a Rc::clone()
, binding a variable to a new &Box
(let a2 = &a;
in the example) will not make it live any longer than it would otherwise.
As a concrete example, the following is valid:
use std::rc::Rc;
fn main() {
let rc_clone;
{
let rc = Rc::new(1);
rc_clone = rc.clone();
// rc gets out of scope here but as a "shared owner", rc_clone
// keeps the underlying data alive.
}
println!("{}", rc_clone); // Ok.
}
But this isn't:
fn main() {
let b_ref;
{
let b = Box::new(1);
b_ref = &b;
// b gets out of scope here and since it is the only owner,
// the underlying data gets dropped.
}
println!("{}", b_ref); // Compilation error: `b` does not live long enough.
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |