Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
0d32bbe
Chapter 15: Smart pointers
steveklabnik Jan 17, 2017
4ad2690
more work on smart pointers
steveklabnik Feb 14, 2017
ac61cbd
finish off draft
steveklabnik Feb 22, 2017
01e407a
First editing pass
carols10cents Feb 23, 2017
092ff98
Address most comments, make more notes
carols10cents Feb 23, 2017
54e807c
A more thorough editing pass
carols10cents Feb 23, 2017
12e12c8
More edits
carols10cents Feb 25, 2017
b07ce30
All but the summary
carols10cents Feb 26, 2017
3af06ba
Whew. Finish editing.
carols10cents Feb 27, 2017
5af5c49
Split into sections
carols10cents Feb 27, 2017
8a39ec9
Connect Drop a bit more to Rc
carols10cents Feb 27, 2017
d2e6325
Multithreaded, one word, is in No Starch's style guide
carols10cents Feb 27, 2017
8d784f7
Finish a sentence
carols10cents Feb 27, 2017
334c10e
Wrap
carols10cents Feb 27, 2017
a251d43
Take awesome suggestions from @matthewjasper
carols10cents Feb 27, 2017
3595078
Start (but not complete) swapping out the weak Weak<T> ex
carols10cents Feb 28, 2017
61d552e
Clarify why we can't call Drop::drop
carols10cents Feb 28, 2017
77f697b
Make section titles consistent and easier to scan
carols10cents Mar 1, 2017
13b10e7
Rejigger intro
carols10cents Mar 1, 2017
aa03fa1
More rejiggering because of @ScottAbbey's excellent comments <3
carols10cents Mar 1, 2017
6672fd6
Another attempt at the Weak<T> example
carols10cents Mar 1, 2017
bf02924
Set up example about borrowing rules on refcell better
carols10cents Mar 1, 2017
b460d00
Remove unnecessary sentence
carols10cents Mar 1, 2017
5c6c1ab
Fix capitalization
carols10cents Mar 1, 2017
e4658ca
Remove File since it doesn't implement Deref
carols10cents Mar 1, 2017
c981fc0
Remove sentence about box being on the stack; not quite true
carols10cents Mar 1, 2017
84255f9
Address most of aturon's comments
carols10cents Mar 1, 2017
52d109f
Try to make examples a bit clearer
carols10cents Mar 1, 2017
90c380c
Try to clarify that RefCell isn't really a smart pointer
carols10cents Mar 2, 2017
72b4ceb
More RefCell clarification
carols10cents Mar 2, 2017
d7ade00
Clarify another instance of immutable data
carols10cents Mar 2, 2017
6646733
Use a sillier example than the non-functioning WebSocket
carols10cents Mar 2, 2017
90ba6d3
Incorporate the Weak example
carols10cents Mar 2, 2017
542013a
See if we can get away with not editing chapter 4
carols10cents Mar 2, 2017
b13b292
Fixing spelling and tests
carols10cents Mar 2, 2017
0e27654
Infinite type illustration
carols10cents Mar 2, 2017
a17e7ca
Add a diagram for Cons with Box
carols10cents Mar 2, 2017
07310e5
Add more figures
carols10cents Mar 2, 2017
87609b1
graphviz is terrible
carols10cents Mar 3, 2017
5f6113d
wrong way arrow
carols10cents Mar 3, 2017
3bfc407
halp can't get arrow pointing the way i want
carols10cents Mar 3, 2017
364ff83
more diagrams
carols10cents Mar 3, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ bool
boolean
booleans
Bors
BorrowMutError
BuildHasher
Cagain
callsite
Expand All @@ -54,14 +55,18 @@ ctrl
Ctrl
deallocated
deallocating
deallocation
debuginfo
deps
deref
Deref
dereference
Dereference
dereferenced
dereferences
dereferencing
DerefMut
destructor
destructure
destructuring
Destructuring
Expand Down Expand Up @@ -158,6 +163,7 @@ monomorphization
Monomorphization
monomorphized
MoveMessage
multithreaded
Mutex
namespace
namespaced
Expand Down Expand Up @@ -197,10 +203,12 @@ RAII
randcrate
READMEs
rect
recurse
redeclaring
Refactoring
refactor
refactoring
refcell
RefCell
repr
retweet
Expand Down Expand Up @@ -264,6 +272,8 @@ typeof
UFCS
unary
Unary
uncomment
Uncomment
Uninstalling
uninstall
unoptimized
Expand All @@ -276,11 +286,13 @@ usize
UsState
utils
variable's
variant's
vers
versa
Versioning
wasn
WeatherForecast
WebSocket
whitespace
wildcards
workspace
Expand Down
6 changes: 6 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@
- [Extending Cargo with Custom Commands](ch14-05-extending-cargo.md)

- [Smart Pointers](ch15-00-smart-pointers.md)
- [`Box<T>` Points to Data on the Heap and Has a Known Size](ch15-01-box.md)
- [The `Deref` Trait Allows Access to the Data Through a Reference](ch15-02-deref.md)
- [The `Drop` Trait Runs Code on Cleanup](ch15-03-drop.md)
- [The Reference Counted Smart Pointer `Rc<T>`](ch15-04-rc.md)
- [The Interior Mutability Pattern and `RefCell<T>`](ch15-05-interior-mutability.md)
- [Creating Reference Cycles and Leaking Memory is Safe](ch15-06-reference-cycles.md)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe these section titles can be fixed up a bit. The first 3 list the name of the thing right at the front, but then the Rc and RefCell ones put their names at the end. If they were all at the front of the section names it would be more consistent and easier to find when flipping pages for a refresher.


- [Concurrency](ch16-00-concurrency.md)

Expand Down
144 changes: 34 additions & 110 deletions src/ch15-00-smart-pointers.md
Original file line number Diff line number Diff line change
@@ -1,112 +1,36 @@
# Smart Pointers

By smart pointers we mean a reference with more characteristics.

Example of something that doesn't work

Surprise! Vec and String are technically smart pointers too!

This chapter is not a comprehensive list, but will give some examples of the
ones in the standard library.


## `Box<T>`

Don't use very often in your own code
Heap allocated
Express Ownership of a heap allocated thing

The three situations to use Box

1. Trait objects
2. Recursive data structures
3. Extend the lifetime of something

How this interacts with the Drop trait

## `Rc<T>`

Reference counted. Rc is for *multiple ownership* - this thing should get
deallocated when all of the owners go out of scope.

Show the data structure:

```rust
struct Rc<T> {
data: Box<T>,
strong_reference_count: usize,
weak_reference_count: usize,
}
```

Talk through this.

This only works if the data is immutable.

What happens when you clone an Rc: data isn't cloned, increase the strong count.
When an Rc clone goes out of scope, the count goes down.

### Rc Cycles

This is how you leak memory in rust, which btw is totally safe.

Is this garbage collecting? Well it's not tracing GC... if you use Rc and had
a cycle detector, it would be functionally equivalent to a tracing GC. Different
runtime characteristics tho.


#### Solution: turn an Rc into a `Weak<T>`

Same as Rc, but doesn't count towards the strong ref count. When you do this, the
strong ref count goes down and the weak count goes up.

Data gets cleaned up when the strong count is 0, no matter what the weak count is.
However, Rc structure is kept until weak reference count also goes to zero, so weak pointers do not become dangling pointers.
At this point, attempt to upgrade Weak pointer will result into None.
Only when weak reference counter also reduces to zero, Rc structure is freed.

## `RefCell<T>`

Single owner of mutable data

The ownership rules checked at runtime instead of compile time.

Only single threaded. See next chapter.

### `borrow` and `borrow_mut` methods

Checks all the rules and panics at runtime if the code violates them.

1. The borrow checker is conservative and people can know more things. (no you
don't, but if you really want to go back to debugging segfaults, feel free)

2. For when you're only allowed to have an immutable thing (which could be `Rc`)
but you need to be able to mutate the underlying data.

## `Cell<T>`

Same thing as RefCell but for types that are Copy. No borrow checking rules here
anyway. So just reason #2 above.

## Is this really safe? Yes!

RefCell is still doing the checks, just at runtime
Cell is safe bc Copy types don't need the ownership rules anyway

### The Interior Mutability Pattern

The Interior Mutability Pattern is super unsafe internally but safe to use
from the outside and is totally safe, totally, trust us, seriously, it's safe.

Allude to `UnsafeCell<T>` maybe. Affects optimizations since &mut T is unique.
UnsafeCell turns off those optimizations so that everything doesn't break.

This is how you can opt-out of the default of Rust's ownership rules and opt
in to different guarantees.

## Summary

If you want to implement your own smart pointer, go read the Nomicon.

Now let's talk about concurrency, and some smart pointers that can be used
with multiple threads.
Now that we've learned quite a bit of Rust, we can start digging into some more
complicated concepts. In this chapter, we'll learn about a design pattern in
Rust called a *smart pointer*. This pattern allows us to leverage Rust's
ownership and borrowing features to manage all kinds of resources in a safe
way, often without much more syntax than using plain old references.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi.

I know next to nothing about this topic so I decided to check out the chapter at this point after it's been given several rounds of scrutiny.

The last sentence of this opening paragraph doesn't mean anything to me. I read it and I don't know anything I didn't know before I read it. I think I know what the ownership and borrowing features are, but can't figure out from this what they're going to be used for in this section.

After peeking ahead to the next paragraph, I think this will be answered, but I just generally don't like introductions that don't actually explain the topic. The last sentence may as well not have been there.


So what are smart pointers, anyway? Well, we've learned about references in
Rust in Chapter 4. *Pointer* is a generic programming term for something like a
reference, that is, pointers "point at" data somewhere else. References are a
kind of pointer that only borrow data; by contrast, in many cases, smart
pointers *own* the data that they point to. They also often hold metadata about
the data. Smart pointers have extra capabilities that references don't, hence
the "smart" nickname.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I rewrite the whole paragraph even though I don't have the slightest idea what I'm talking about?

I can try!

So what are smart pointers, anyway? Pointer is a generic programming term for something that refers to another value. We already learned about a simple kind of pointer in Chapter 4; Rust's references (indicated by the & symbol) borrow the value that they point to. Smart pointers are like references with extra capabilities. Many smart pointers own the data that they point to instead of just borrowing it. They also often hold metadata about the data.


We've actually already encountered a few smart pointers in this book, we didn't
call them that by name, though. For example, in a certain sense, `String` and
`Vec<T>` from Chapter 8 are both smart pointers. They own some memory and allow
you to manipulate it, and have metadata (like their capacity) and extra
capabilities or guarantees (`String` data will always be valid UTF-8). Another
good example is `File`, which we used for our I/O project in Chapter 12: it
owns and manages a file handle that the operating system gives us, and allows
us to access the data in the file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading this paragraph I have decided that any old struct with a few methods and traits is a smart pointer. If that isn't quite right, it might need some rework.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specifically, it needs to have deref and Drop


Given that this is a general design pattern in Rust, this chapter won't cover
every smart pointer that exists. Many libraries will build their own as well,
and you may write some for your own code. The ones we cover here will be the
Copy link
Contributor

@ScottAbbey ScottAbbey Feb 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many libraries have their own and you may write some yourself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ones we cover here will be the...

Does "will be" match "we cover here"? Maybe "are" instead? Or "we will cover".

most common ones from the standard library: `Box<T>`, `Rc<T>`, and
`RefCell<T>`. Along the way, we'll also cover:

* The `Deref` and `Drop` traits that make smart pointers convenient to work with
* The *interior mutability* pattern that lets you...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't finished

* Reference cycles, how they can leak memory, and how to prevent them

Let's dive in!
Loading