]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## `Rc<T>`, the Reference Counted Smart Pointer |
2 | ||
3 | In the majority of cases, ownership is clear: you know exactly which variable | |
4 | owns a given value. However, there are cases when a single value might have | |
5 | multiple owners. For example, in graph data structures, multiple edges might | |
6 | point to the same node, and that node is conceptually owned by all of the edges | |
7 | that point to it. A node shouldn’t be cleaned up unless it doesn’t have any | |
8 | edges pointing to it. | |
9 | ||
10 | To enable multiple ownership, Rust has a type called `Rc<T>`, which is an | |
11 | abbreviation for *reference counting*. The `Rc<T>` type keeps track of the | |
136023e0 XL |
12 | number of references to a value to determine whether or not the value is still |
13 | in use. If there are zero references to a value, the value can be cleaned up | |
14 | without any references becoming invalid. | |
13cf67c4 XL |
15 | |
16 | Imagine `Rc<T>` as a TV in a family room. When one person enters to watch TV, | |
17 | they turn it on. Others can come into the room and watch the TV. When the last | |
18 | person leaves the room, they turn off the TV because it’s no longer being used. | |
19 | If someone turns off the TV while others are still watching it, there would be | |
20 | uproar from the remaining TV watchers! | |
21 | ||
22 | We use the `Rc<T>` type when we want to allocate some data on the heap for | |
23 | multiple parts of our program to read and we can’t determine at compile time | |
24 | which part will finish using the data last. If we knew which part would finish | |
25 | last, we could just make that part the data’s owner, and the normal ownership | |
26 | rules enforced at compile time would take effect. | |
27 | ||
28 | Note that `Rc<T>` is only for use in single-threaded scenarios. When we discuss | |
29 | concurrency in Chapter 16, we’ll cover how to do reference counting in | |
30 | multithreaded programs. | |
31 | ||
32 | ### Using `Rc<T>` to Share Data | |
33 | ||
34 | Let’s return to our cons list example in Listing 15-5. Recall that we defined | |
35 | it using `Box<T>`. This time, we’ll create two lists that both share ownership | |
36 | of a third list. Conceptually, this looks similar to Figure 15-3: | |
37 | ||
38 | <img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" /> | |
39 | ||
40 | <span class="caption">Figure 15-3: Two lists, `b` and `c`, sharing ownership of | |
41 | a third list, `a`</span> | |
42 | ||
43 | We’ll create list `a` that contains 5 and then 10. Then we’ll make two more | |
44 | lists: `b` that starts with 3 and `c` that starts with 4. Both `b` and `c` | |
45 | lists will then continue on to the first `a` list containing 5 and 10. In other | |
46 | words, both lists will share the first list containing 5 and 10. | |
47 | ||
48 | Trying to implement this scenario using our definition of `List` with `Box<T>` | |
49 | won’t work, as shown in Listing 15-17: | |
50 | ||
51 | <span class="filename">Filename: src/main.rs</span> | |
52 | ||
53 | ```rust,ignore,does_not_compile | |
74b04a01 | 54 | {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-17/src/main.rs}} |
13cf67c4 XL |
55 | ``` |
56 | ||
57 | <span class="caption">Listing 15-17: Demonstrating we’re not allowed to have | |
58 | two lists using `Box<T>` that try to share ownership of a third list</span> | |
59 | ||
60 | When we compile this code, we get this error: | |
61 | ||
f035d41b | 62 | ```console |
74b04a01 | 63 | {{#include ../listings/ch15-smart-pointers/listing-15-17/output.txt}} |
13cf67c4 XL |
64 | ``` |
65 | ||
66 | The `Cons` variants own the data they hold, so when we create the `b` list, `a` | |
67 | is moved into `b` and `b` owns `a`. Then, when we try to use `a` again when | |
68 | creating `c`, we’re not allowed to because `a` has been moved. | |
69 | ||
70 | We could change the definition of `Cons` to hold references instead, but then | |
71 | we would have to specify lifetime parameters. By specifying lifetime | |
72 | parameters, we would be specifying that every element in the list will live at | |
73 | least as long as the entire list. The borrow checker wouldn’t let us compile | |
74 | `let a = Cons(10, &Nil);` for example, because the temporary `Nil` value would | |
75 | be dropped before `a` could take a reference to it. | |
76 | ||
77 | Instead, we’ll change our definition of `List` to use `Rc<T>` in place of | |
78 | `Box<T>`, as shown in Listing 15-18. Each `Cons` variant will now hold a value | |
79 | and an `Rc<T>` pointing to a `List`. When we create `b`, instead of taking | |
80 | ownership of `a`, we’ll clone the `Rc<List>` that `a` is holding, thereby | |
81 | increasing the number of references from one to two and letting `a` and `b` | |
82 | share ownership of the data in that `Rc<List>`. We’ll also clone `a` when | |
83 | creating `c`, increasing the number of references from two to three. Every time | |
84 | we call `Rc::clone`, the reference count to the data within the `Rc<List>` will | |
85 | increase, and the data won’t be cleaned up unless there are zero references to | |
86 | it. | |
87 | ||
88 | <span class="filename">Filename: src/main.rs</span> | |
89 | ||
90 | ```rust | |
74b04a01 | 91 | {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-18/src/main.rs}} |
13cf67c4 XL |
92 | ``` |
93 | ||
94 | <span class="caption">Listing 15-18: A definition of `List` that uses | |
95 | `Rc<T>`</span> | |
96 | ||
97 | We need to add a `use` statement to bring `Rc<T>` into scope because it’s not | |
98 | in the prelude. In `main`, we create the list holding 5 and 10 and store it in | |
99 | a new `Rc<List>` in `a`. Then when we create `b` and `c`, we call the | |
100 | `Rc::clone` function and pass a reference to the `Rc<List>` in `a` as an | |
101 | argument. | |
102 | ||
103 | We could have called `a.clone()` rather than `Rc::clone(&a)`, but Rust’s | |
104 | convention is to use `Rc::clone` in this case. The implementation of | |
105 | `Rc::clone` doesn’t make a deep copy of all the data like most types’ | |
106 | implementations of `clone` do. The call to `Rc::clone` only increments the | |
107 | reference count, which doesn’t take much time. Deep copies of data can take a | |
108 | lot of time. By using `Rc::clone` for reference counting, we can visually | |
109 | distinguish between the deep-copy kinds of clones and the kinds of clones that | |
110 | increase the reference count. When looking for performance problems in the | |
111 | code, we only need to consider the deep-copy clones and can disregard calls to | |
112 | `Rc::clone`. | |
113 | ||
114 | ### Cloning an `Rc<T>` Increases the Reference Count | |
115 | ||
116 | Let’s change our working example in Listing 15-18 so we can see the reference | |
117 | counts changing as we create and drop references to the `Rc<List>` in `a`. | |
118 | ||
119 | In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`; | |
120 | then we can see how the reference count changes when `c` goes out of scope. | |
121 | ||
122 | <span class="filename">Filename: src/main.rs</span> | |
123 | ||
124 | ```rust | |
74b04a01 | 125 | {{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-19/src/main.rs:here}} |
13cf67c4 XL |
126 | ``` |
127 | ||
128 | <span class="caption">Listing 15-19: Printing the reference count</span> | |
129 | ||
130 | At each point in the program where the reference count changes, we print the | |
131 | reference count, which we can get by calling the `Rc::strong_count` function. | |
132 | This function is named `strong_count` rather than `count` because the `Rc<T>` | |
133 | type also has a `weak_count`; we’ll see what `weak_count` is used for in the | |
9fa01778 XL |
134 | [“Preventing Reference Cycles: Turning an `Rc<T>` into a |
135 | `Weak<T>`”][preventing-ref-cycles]<!-- ignore --> section. | |
13cf67c4 XL |
136 | |
137 | This code prints the following: | |
138 | ||
f035d41b | 139 | ```console |
74b04a01 | 140 | {{#include ../listings/ch15-smart-pointers/listing-15-19/output.txt}} |
13cf67c4 XL |
141 | ``` |
142 | ||
143 | We can see that the `Rc<List>` in `a` has an initial reference count of 1; then | |
144 | each time we call `clone`, the count goes up by 1. When `c` goes out of scope, | |
145 | the count goes down by 1. We don’t have to call a function to decrease the | |
146 | reference count like we have to call `Rc::clone` to increase the reference | |
147 | count: the implementation of the `Drop` trait decreases the reference count | |
148 | automatically when an `Rc<T>` value goes out of scope. | |
149 | ||
150 | What we can’t see in this example is that when `b` and then `a` go out of scope | |
151 | at the end of `main`, the count is then 0, and the `Rc<List>` is cleaned up | |
152 | completely at that point. Using `Rc<T>` allows a single value to have | |
153 | multiple owners, and the count ensures that the value remains valid as long as | |
154 | any of the owners still exist. | |
155 | ||
156 | Via immutable references, `Rc<T>` allows you to share data between multiple | |
157 | parts of your program for reading only. If `Rc<T>` allowed you to have multiple | |
158 | mutable references too, you might violate one of the borrowing rules discussed | |
159 | in Chapter 4: multiple mutable borrows to the same place can cause data races | |
160 | and inconsistencies. But being able to mutate data is very useful! In the next | |
161 | section, we’ll discuss the interior mutability pattern and the `RefCell<T>` | |
162 | type that you can use in conjunction with an `Rc<T>` to work with this | |
163 | immutability restriction. | |
9fa01778 XL |
164 | |
165 | [preventing-ref-cycles]: ch15-06-reference-cycles.html#preventing-reference-cycles-turning-an-rct-into-a-weakt |