|
1 |
| -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
| 1 | +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT |
2 | 2 | // file at the top-level directory of this distribution and at
|
3 | 3 | // http://rust-lang.org/COPYRIGHT.
|
4 | 4 | //
|
|
10 | 10 |
|
11 | 11 | /*! Task-local reference-counted boxes (`Rc` type)
|
12 | 12 |
|
13 |
| -The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, and |
14 |
| -will occur as soon as the last owner is gone. It is marked as non-sendable because it avoids the |
15 |
| -overhead of atomic reference counting. |
| 13 | +The `Rc` type provides shared ownership of an immutable value. Destruction is |
| 14 | +deterministic, and will occur as soon as the last owner is gone. It is marked |
| 15 | +as non-sendable because it avoids the overhead of atomic reference counting. |
16 | 16 |
|
17 |
| -The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A `Weak` |
18 |
| -pointer can be upgraded to an `Rc` pointer, but will return `None` if the value has already been |
19 |
| -freed. |
| 17 | +The `downgrade` method can be used to create a non-owning `Weak` pointer to the |
| 18 | +box. A `Weak` pointer can be upgraded to an `Rc` pointer, but will return |
| 19 | +`None` if the value has already been freed. |
20 | 20 |
|
21 |
| -For example, a tree with parent pointers can be represented by putting the nodes behind `Strong` |
22 |
| -pointers, and then storing the parent pointers as `Weak` pointers. |
| 21 | +For example, a tree with parent pointers can be represented by putting the |
| 22 | +nodes behind strong `Rc` pointers, and then storing the parent pointers as |
| 23 | +`Weak` pointers. |
| 24 | +
|
| 25 | +
|
| 26 | +## Examples |
| 27 | +
|
| 28 | +Consider a scenario where a set of Gadgets are owned by a given Owner. We want |
| 29 | +to have our Gadgets point to their Owner. We can't do this with unique |
| 30 | +ownership, because more than one gadget may belong to the same Owner. Rc |
| 31 | +allows us to share an Owner between multiple Gadgets, and have the Owner kept |
| 32 | +alive as long as any Gadget points at it. |
| 33 | +
|
| 34 | +```rust |
| 35 | +use std::rc::Rc; |
| 36 | +
|
| 37 | +struct Owner { |
| 38 | + name: String |
| 39 | + // ...other fields |
| 40 | +} |
| 41 | +
|
| 42 | +struct Gadget { |
| 43 | + id: int, |
| 44 | + owner: Rc<Owner> |
| 45 | + // ...other fields |
| 46 | +} |
| 47 | +
|
| 48 | +fn main() { |
| 49 | + // Create a reference counted Owner. |
| 50 | + let gadget_owner : Rc<Owner> = Rc::new( |
| 51 | + Owner { name: String::from_str("Gadget Man") } |
| 52 | + ); |
| 53 | +
|
| 54 | + // Create Gadgets belonging to gadget_owner. To increment the reference |
| 55 | + // count we clone the Rc object. |
| 56 | + let gadget1 = Gadget { id: 1, owner: gadget_owner.clone() }; |
| 57 | + let gadget2 = Gadget { id: 2, owner: gadget_owner.clone() }; |
| 58 | +
|
| 59 | + drop(gadget_owner); |
| 60 | +
|
| 61 | + // Despite dropping gadget_owner, we're still able to print out the name of |
| 62 | + // the Owner of the Gadgets. This is because we've only dropped the |
| 63 | + // reference count object, not the Owner it wraps. As long as there are |
| 64 | + // other Rc objects pointing at the same Owner, it will stay alive. Notice |
| 65 | + // that the Rc wrapper around Gadget.owner gets automatically dereferenced |
| 66 | + // for us. |
| 67 | + println!("Gadget {} owned by {}", gadget1.id, gadget1.owner.name); |
| 68 | + println!("Gadget {} owned by {}", gadget2.id, gadget2.owner.name); |
| 69 | +
|
| 70 | + // At the end of the method, gadget1 and gadget2 get destroyed, and with |
| 71 | + // them the last counted references to our Owner. Gadget Man now gets |
| 72 | + // destroyed as well. |
| 73 | +} |
| 74 | +``` |
| 75 | +
|
| 76 | +If our requirements change, and we also need to be able to traverse from |
| 77 | +Owner->Gadget, we will run into problems: an Rc pointer from Owner->Gadget |
| 78 | +introduces a cycle between the objects. This means that their reference counts |
| 79 | +can never reach 0, and the objects will stay alive: a memory leak. In order to |
| 80 | +get around this, we can use `Weak` pointers. These are reference counted |
| 81 | +pointers that don't keep an object alive if there are no normal `Rc` (or |
| 82 | +*strong*) pointers left. |
| 83 | +
|
| 84 | +Rust actually makes it somewhat difficult to produce this loop in the first |
| 85 | +place: in order to end up with two objects that point at each other, one of |
| 86 | +them needs to be mutable. This is problematic because Rc enforces memory |
| 87 | +safety by only giving out shared references to the object it wraps, and these |
| 88 | +don't allow direct mutation. We need to wrap the part of the object we wish to |
| 89 | +mutate in a `RefCell`, which provides *interior mutability*: a method to |
| 90 | +achieve mutability through a shared reference. `RefCell` enforces Rust's |
| 91 | +borrowing rules at runtime. Read the `Cell` documentation for more details on |
| 92 | +interior mutability. |
| 93 | +
|
| 94 | +```rust |
| 95 | +use std::rc::Rc; |
| 96 | +use std::rc::Weak; |
| 97 | +use std::cell::RefCell; |
| 98 | +
|
| 99 | +struct Owner { |
| 100 | + name: String, |
| 101 | + gadgets: RefCell<Vec<Weak<Gadget>>> |
| 102 | + // ...other fields |
| 103 | +} |
| 104 | +
|
| 105 | +struct Gadget { |
| 106 | + id: int, |
| 107 | + owner: Rc<Owner> |
| 108 | + // ...other fields |
| 109 | +} |
| 110 | +
|
| 111 | +fn main() { |
| 112 | + // Create a reference counted Owner. Note the fact that we've put the |
| 113 | + // Owner's vector of Gadgets inside a RefCell so that we can mutate it |
| 114 | + // through a shared reference. |
| 115 | + let gadget_owner : Rc<Owner> = Rc::new( |
| 116 | + Owner { |
| 117 | + name: "Gadget Man".to_string(), |
| 118 | + gadgets: RefCell::new(Vec::new()) |
| 119 | + } |
| 120 | + ); |
| 121 | +
|
| 122 | + // Create Gadgets belonging to gadget_owner as before. |
| 123 | + let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()}); |
| 124 | + let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()}); |
| 125 | +
|
| 126 | + // Add the Gadgets to their Owner. To do this we mutably borrow from |
| 127 | + // the RefCell holding the Owner's Gadgets. |
| 128 | + gadget_owner.gadgets.borrow_mut().push(gadget1.clone().downgrade()); |
| 129 | + gadget_owner.gadgets.borrow_mut().push(gadget2.clone().downgrade()); |
| 130 | +
|
| 131 | + // Iterate over our Gadgets, printing their details out |
| 132 | + for gadget_opt in gadget_owner.gadgets.borrow().iter() { |
| 133 | +
|
| 134 | + // gadget_opt is a Weak<Gadget>. Since weak pointers can't guarantee |
| 135 | + // that their object is still alive, we need to call upgrade() on them |
| 136 | + // to turn them into a strong reference. This returns an Option, which |
| 137 | + // contains a reference to our object if it still exists. |
| 138 | + let gadget = gadget_opt.upgrade().unwrap(); |
| 139 | + println!("Gadget {} owned by {}", gadget.id, gadget.owner.name); |
| 140 | + } |
| 141 | +
|
| 142 | + // At the end of the method, gadget_owner, gadget1 and gadget2 get |
| 143 | + // destroyed. There are now no strong (Rc) references to the gadgets. |
| 144 | + // Once they get destroyed, the Gadgets get destroyed. This zeroes the |
| 145 | + // reference count on Gadget Man, so he gets destroyed as well. |
| 146 | +} |
| 147 | +``` |
23 | 148 |
|
24 | 149 | */
|
25 | 150 |
|
|
0 commit comments