<style>
/* basic design */
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6,
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {
font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic';
text-align: left;
line-height: 1.5;
letter-spacing: normal;
text-shadow: none;
word-wrap: break-word;
color: #AAA;
}
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {font-weight: bold;}
.reveal h1, .reveal h2, .reveal h3 {color: #2980b9;}
.reveal th {background: #DDD;}
.reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;}
.reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;}
.reveal table {margin: 1.0vw auto;}
.reveal code {line-height: 1.2;}
.reveal p, .reveal li {padding: 0vw; margin: 0vw;}
.reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;}
/* table design */
.reveal table {background: #f5f5f5;}
.reveal th {background: #444; color: #fff;}
.reveal td {position: relative; transition: all 300ms;}
.reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #AAA;}
.reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #CCC;}
/* blockquote design */
.reveal blockquote {
width: 90%;
padding: 0.5vw 0 0.5vw 6.0vw;
font-style: italic;
background: #f5f5f5;
}
.reveal blockquote:before{
position: absolute;
top: 0.1vw;
left: 1vw;
content: "\f10d";
font-family: FontAwesome;
color: #2980b9;
font-size: 3.0vw;
}
/* font size */
.reveal h1 {font-size: 4.0vw;}
.reveal h2 {font-size: 3.5vw;}
.reveal h3 {font-size: 2.8vw;}
.reveal h4 {font-size: 2.6vw;}
.reveal h5 {font-size: 2.4vw;}
.reveal h6 {font-size: 2.2vw;}
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.0vw;}
.reveal code {font-size: 1.0vw;}
/* new color */
.red {color: #EE6557;}
.blue {color: #16A6B6;}
/* split slide */
#right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;}
#left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;}
</style>
<style>
/* specific design */
.reveal h2 {
padding: 0 1.5vw;
margin: 0.0vw 0 2.0vw -2.0vw;
border-left: solid 1.0vw #2980b9;
border-bottom: solid 0.6vw #d7d7d7;
}
</style>
<!-- --------------------------------------------------------------------------------------- -->
# Rust Study Session \#15
## Ch.15 (part 1) - Smart Pointers
### 2020.11.13 - Salvatore La Bua
---
## Summary
- What is a pointer.
- Using __Box\<T\>__ to point to data on the heap.
- Smart Pointers as regular references.
- Running code on cleanup.
- __Rc\<T\>__, the Reference Counted smart pointer.
---
## Pointers
### What is a pointer
- In general, a pointer is a variable that contains an address in memory.
- Such address refers to some other data.
---
### Reference
- Most common type of pointer is the __reference__.
- Indicated by __&__, only borrows the value it points to.
- References are simple pointers.
- There is no overhead.
---
### Smart Pointers
- Data structures with additional metadata capabilities.
- Can own the data they point to.
- Originated in C++, also available in other languages.
---
### Smart Pointers
- __String__
- __Vec\<T\>__
- __Reference Counting__ smart pointer type:
- Keeps track of data owners.
- Clean up when no more owners remain.
---
### Smart Pointers
- Usually implemented as Structs.
- Implement the Deref and Drop traits:
- __Deref__: to behave as a Reference.
- __Drop__: behaviour when getting out of scope.
---
### Smart Pointers
- __Box\<T\>__ for allocating values on the heap.
- __Rc\<T\>__ to enable multiple ownership.
- (Ref\<T\> and RefMut\<T\>, accessed through RefCell\<T\>)
- (Interior mutability and reference cycles)
---
## Using __Box\<T\>__ to point to data
- Only the pointer is stored on the stack.
- The data is stored on the heap.
- No performance overhead.
---
### __Box\<T\>__ to point data
#### Use when:
- A type size is not know at compile time.
- Transfer ownership of a large amount of data without copying the data itself.
- To own a value for which its type implements a particular trait.
---
### __Box\<T\>__ to store data
```rust=
fn main() {
// Box points to 5 allocated on the heap
let b = Box::new(5);
println!("b = {}", b);
}
```
---
### __Box\<T\>__
#### Enabling recursive types
- The size of a recursive type can not be known at compile time.
- Boxes have a known size, therefore they can be used in recursive types.
---
### Cons List
#### Example
```rust=
enum List {
Cons(i32, List),
Nil,
}
```
Equivalent to
```rust=
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
```
---
### Cons List
![](https://doc.rust-lang.org/book/img/trpl15-01.svg)
---
### Cons List
#### Compilation of recursive types
```bash=
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
error[E0072]: recursive type `List` has infinite size
--> src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^ recursive type has infinite size
2 | Cons(i32, List),
| ---- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable
error[E0391]: cycle detected when processing `List`
--> src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
|
= note : ...which again requires processing `List`, completing the cycle
= note : cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, def_id: None }, value: List } }`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0072, E0391.
For more information about an error, try `rustc --explain E0072`.
error: could not compile `cons-list`.
To learn more, run the command again with --verbose.
```
---
### Cons List (using Box\<T\>)
```rust=
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
```
---
### Cons List (using Box\<T\>)
![](https://doc.rust-lang.org/book/img/trpl15-02.svg)
<div style="text-align: right">□</div>
---
## Smart Pointers as a Reference
### The Deref trait
Customise the behaviour of the *deference operator* __*__
---
### Regular references
```rust=
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y); // using the deference operator
}
```
---
### Box\<T\> as a reference
```rust=
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y); // using the deference operator
}
```
---
### Using a custom smart pointer
```rust=
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
```
```rust=
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
```
---
### Using a custom smart pointer
```bash=
$ cargo run
Compiling deref-example v0.1.0 (file:///projects/deref-example)
error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
--> src/main.rs:14:19
|
14 | assert_eq!(5, *y);
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0614`.
error: could not compile `deref-example`.
To learn more, run the command again with --verbose.
```
---
### Using a custom smart pointer
#### Implementing the Deref trait
```rust=
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
```
---
### Deref coercion
Converts a type that implement the deref trait into a reference to another type.
#### Example
```rust=
fn hello(name: &str) {
println!("Hello, {}!", name);
}
```
```rust=
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&m);
}
```
---
### Defer coercion and mutability
Use the __DerefMut__ trait to override the * operator on mutable references.
- From &T to &U when T: Deref\<Target=U\>
- From &mut T to &mut U when T: DerefMut\<Target=U\>
- From &mut T to &U when T: Deref\<Target=U\>
<div style="text-align: right">□</div>
---
## Running code on cleanup
### The Drop trait
```rust=
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
```
---
### The Drop trait
```rust=
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
```
```bash=
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished dev [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/drop-example`
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
```
---
### Dropping a value early
```rust=
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
c.drop();
println!("CustomSmartPointer dropped before the end of main.");
}
```
```bash=
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
--> src/main.rs:16:7
|
16 | c.drop();
| ^^^^ explicit destructor calls not allowed
error: aborting due to previous error
```
---
### Dropping a value early (fix)
```rust=
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c); // std::mem::drop
println!("CustomSmartPointer dropped before the end of main.");
}
```
```bash=
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished dev [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.
```
<div style="text-align: right">□</div>
---
## Rc\<T\>, the Reference Counted smart pointer
A single value might have multiple owners.
---
### Implement a graph
```rust=
use crate::List::{Cons, Nil};
fn main() {
let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
let b = Cons(3, Box::new(a));
let c = Cons(4, Box::new(a));
}
```
![](https://doc.rust-lang.org/book/img/trpl15-03.svg)
---
### Implement a graph
```bash=
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
error[E0382]: use of moved value: `a`
--> src/main.rs:11:30
|
9 | let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
| - move occurs because `a` has type `List`, which does not implement the `Copy` trait
10 | let b = Cons(3, Box::new(a));
| - value moved here
11 | let c = Cons(4, Box::new(a));
| ^ value used here after move
error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
error: could not compile `cons-list`.
To learn more, run the command again with --verbose.
```
---
### Implement a graph (fix)
```rust=
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
}
```
---
### Implement a graph (rc check)
```rust=
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}
```
---
### Implement a graph (rc check)
```bash=
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
Finished dev [unoptimized + debuginfo] target(s) in 0.45s
Running `target/debug/cons-list`
count after creating a = 1
count after creating b = 2
count after creating c = 3
count after c goes out of scope = 2
```
<div style="text-align: right">□</div>
---
## References
From __The Rust Programming Language__ book:
- Ch. 15: Smart Pointers [[EN]](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) [[JP]](https://doc.rust-jp.rs/book-ja/ch15-00-smart-pointers.html)
---
{"metaMigratedAt":"2023-06-15T15:32:30.217Z","metaMigratedFrom":"YAML","title":"Rust Ch.15 (part 1) - Smart Pointers","breaks":true,"description":"Rust Ch.15 (part 1) - Smart Pointers","slideOptions":"{\"theme\":\"black\",\"slideNumber\":\"c/t\",\"center\":false,\"transition\":\"fade\",\"keyboard\":true}","contributors":"[{\"id\":\"c5f0d40d-be35-4660-a8b4-7736feeb9327\",\"add\":27222,\"del\":13937}]"}