mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Wording tweaks
This commit is contained in:
parent
ac1d473ac2
commit
f7a5fea93d
@ -75,16 +75,20 @@ we'll follow this guide:
|
|||||||
- Boxed closures (FnBox, others?) are heap allocated
|
- Boxed closures (FnBox, others?) are heap allocated
|
||||||
- "Move" semantics don't trigger new allocation; just a change of ownership,
|
- "Move" semantics don't trigger new allocation; just a change of ownership,
|
||||||
so are incredibly fast
|
so are incredibly fast
|
||||||
|
- In examples, is address of data before and after the same?
|
||||||
|
- Can `Copy` trigger allocation?
|
||||||
- Stack-based alternatives to standard library types should be preferred (spin, parking_lot)
|
- Stack-based alternatives to standard library types should be preferred (spin, parking_lot)
|
||||||
|
|
||||||
## Smart pointers
|
# Smart pointers
|
||||||
|
|
||||||
The first thing to note are the "smart pointer" types.
|
The first thing to note are the "smart pointer" types.
|
||||||
When you have data that must outlive the scope in which it is declared,
|
When you have data that must outlive the scope in which it is declared,
|
||||||
or your data is of unknown or dynamic size, you'll make use of these types.
|
or your data is of unknown or dynamic size, you'll make use of these types.
|
||||||
|
|
||||||
The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer)
|
The term [smart pointer](https://en.wikipedia.org/wiki/Smart_pointer)
|
||||||
comes from C++, and is used to describe objects that are responsible for managing
|
comes from C++, and while it's closely linked to a general design pattern of
|
||||||
|
["Resource Acquisition Is Initialization"](https://en.cppreference.com/w/cpp/language/raii),
|
||||||
|
we'll use it here specifically to describe objects that are responsible for managing
|
||||||
ownership of data allocated on the heap. The smart pointers available in the `alloc`
|
ownership of data allocated on the heap. The smart pointers available in the `alloc`
|
||||||
crate should look mostly familiar:
|
crate should look mostly familiar:
|
||||||
- [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
|
- [`Box`](https://doc.rust-lang.org/alloc/boxed/struct.Box.html)
|
||||||
@ -97,10 +101,10 @@ though more than can be covered in this article. Some examples:
|
|||||||
- [`RwLock`](https://doc.rust-lang.org/std/sync/struct.RwLock.html)
|
- [`RwLock`](https://doc.rust-lang.org/std/sync/struct.RwLock.html)
|
||||||
- [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
|
- [`Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
|
||||||
|
|
||||||
Finally, there is one [gotcha](https://www.merriam-webster.com/dictionary/gotcha):
|
Finally, there is one ["gotcha"](https://www.merriam-webster.com/dictionary/gotcha):
|
||||||
cell types (like [`RefCell`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html))
|
cell types (like [`RefCell`](https://doc.rust-lang.org/stable/core/cell/struct.RefCell.html))
|
||||||
look and behave like smart pointers, but don't actually require heap allocation.
|
follow the RAII pattern, but don't involve heap allocation. Check out the
|
||||||
Check out the [`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
|
[`core::cell` docs](https://doc.rust-lang.org/stable/core/cell/index.html)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
When a smart pointer is created, the data it is given is placed in heap memory and
|
When a smart pointer is created, the data it is given is placed in heap memory and
|
||||||
@ -138,7 +142,7 @@ pub fn my_cow() {
|
|||||||
```
|
```
|
||||||
-- [Compiler Explorer](https://godbolt.org/z/SaDpWg)
|
-- [Compiler Explorer](https://godbolt.org/z/SaDpWg)
|
||||||
|
|
||||||
## Collections
|
# Collections
|
||||||
|
|
||||||
Collections types use heap memory because they have dynamic size; they will request more memory
|
Collections types use heap memory because they have dynamic size; they will request more memory
|
||||||
[when needed](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve),
|
[when needed](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve),
|
||||||
|
@ -30,7 +30,7 @@ we're just focused on interesting things the Rust language can do.
|
|||||||
The guiding principal as we move forward is this: *optimizing compilers
|
The guiding principal as we move forward is this: *optimizing compilers
|
||||||
won't produce worse assembly than we started with.* There won't be any
|
won't produce worse assembly than we started with.* There won't be any
|
||||||
situations where stack allocations get moved to heap allocations.
|
situations where stack allocations get moved to heap allocations.
|
||||||
There will, however, be an opera of optimization.
|
There will, however, be an opera of optimization.
|
||||||
|
|
||||||
# The Case of the Disappearing Box
|
# The Case of the Disappearing Box
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ With all that in mind, let's talk about situations in which we're guaranteed to
|
|||||||
- Closures capture their arguments on the stack
|
- Closures capture their arguments on the stack
|
||||||
- Generics will use stack allocation, even with dynamic dispatch.
|
- Generics will use stack allocation, even with dynamic dispatch.
|
||||||
|
|
||||||
## Structs
|
# Structs
|
||||||
|
|
||||||
The simplest case comes first. When creating vanilla `struct` objects, we use stack memory
|
The simplest case comes first. When creating vanilla `struct` objects, we use stack memory
|
||||||
to hold their contents:
|
to hold their contents:
|
||||||
@ -132,7 +132,7 @@ pub fn make_line() {
|
|||||||
Note that while some extra-fancy instructions are used for memory manipulation in the assembly,
|
Note that while some extra-fancy instructions are used for memory manipulation in the assembly,
|
||||||
the `sub rsp, 64` instruction indicates we're still working with the stack.
|
the `sub rsp, 64` instruction indicates we're still working with the stack.
|
||||||
|
|
||||||
## Function arguments
|
# Function arguments
|
||||||
|
|
||||||
Have you ever wondered how functions communicate with each other? Like, once the variables are
|
Have you ever wondered how functions communicate with each other? Like, once the variables are
|
||||||
given to you, everything's fine. But how do you "give" those variables to another function?
|
given to you, everything's fine. But how do you "give" those variables to another function?
|
||||||
@ -237,7 +237,7 @@ and passing by reference (either moving ownership or passing a pointer) may have
|
|||||||
[slightly different layouts in assembly](https://godbolt.org/z/sKi_kl), but will
|
[slightly different layouts in assembly](https://godbolt.org/z/sKi_kl), but will
|
||||||
still use either stack memory or CPU registers.
|
still use either stack memory or CPU registers.
|
||||||
|
|
||||||
## Enums
|
# Enums
|
||||||
|
|
||||||
If you've ever worried that wrapping your types in
|
If you've ever worried that wrapping your types in
|
||||||
[`Option`](https://doc.rust-lang.org/stable/core/option/enum.Option.html) or
|
[`Option`](https://doc.rust-lang.org/stable/core/option/enum.Option.html) or
|
||||||
@ -275,7 +275,7 @@ in assembly, so I'll instead point you to the
|
|||||||
[`core::mem::size_of`](https://doc.rust-lang.org/stable/core/mem/fn.size_of.html#size-of-enums)
|
[`core::mem::size_of`](https://doc.rust-lang.org/stable/core/mem/fn.size_of.html#size-of-enums)
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
## Arrays
|
# Arrays
|
||||||
|
|
||||||
The array type is guaranteed to be stack allocated, which is why the array size must
|
The array type is guaranteed to be stack allocated, which is why the array size must
|
||||||
be declared. Interestingly enough, this can be used to cause safe Rust programs to crash:
|
be declared. Interestingly enough, this can be used to cause safe Rust programs to crash:
|
||||||
@ -320,7 +320,7 @@ There aren't any security implications of this (no memory corruption occurs),
|
|||||||
but it's good to note that the Rust compiler won't move arrays into heap memory
|
but it's good to note that the Rust compiler won't move arrays into heap memory
|
||||||
even if they can be reasonably expected to overflow the stack.
|
even if they can be reasonably expected to overflow the stack.
|
||||||
|
|
||||||
## Closures
|
# Closures
|
||||||
|
|
||||||
Rules for how anonymous functions capture their arguments are typically language-specific.
|
Rules for how anonymous functions capture their arguments are typically language-specific.
|
||||||
In Java, [Lambda Expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
|
In Java, [Lambda Expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)
|
||||||
@ -387,7 +387,7 @@ pub fn complex() {
|
|||||||
|
|
||||||
In every circumstance though, the compiler ensured that no heap allocations were necessary.
|
In every circumstance though, the compiler ensured that no heap allocations were necessary.
|
||||||
|
|
||||||
## Generics
|
# Generics
|
||||||
|
|
||||||
Traits in Rust come in two broad forms: static dispatch (monomorphization, `impl Trait`)
|
Traits in Rust come in two broad forms: static dispatch (monomorphization, `impl Trait`)
|
||||||
and dynamic dispatch (trait objects, `dyn Trait`). While dynamic dispatch is often
|
and dynamic dispatch (trait objects, `dyn Trait`). While dynamic dispatch is often
|
||||||
@ -444,5 +444,5 @@ pub fn do_call() {
|
|||||||
```
|
```
|
||||||
-- [Compiler Explorer](https://godbolt.org/z/u_yguS)
|
-- [Compiler Explorer](https://godbolt.org/z/u_yguS)
|
||||||
|
|
||||||
It's hard to imagine practical situations where dynamic dispatch
|
It's hard to imagine practical situations where dynamic dispatch would be
|
||||||
would be used for objects that aren't heap allocated, but it can be done.
|
used for objects that aren't heap allocated, but it technically can be done.
|
@ -16,7 +16,7 @@ we'll go into below. The
|
|||||||
[full specification](https://github.com/rust-lang/rfcs/blob/master/text/0246-const-vs-static.md)
|
[full specification](https://github.com/rust-lang/rfcs/blob/master/text/0246-const-vs-static.md)
|
||||||
for these two memory types is available, but we'll take a hands-on approach to the topic.
|
for these two memory types is available, but we'll take a hands-on approach to the topic.
|
||||||
|
|
||||||
## **const**
|
# **const**
|
||||||
|
|
||||||
The quick summary is this: `const` declares a read-only block of memory that is loaded
|
The quick summary is this: `const` declares a read-only block of memory that is loaded
|
||||||
as part of your program binary (during the call to [exec(3)](https://linux.die.net/man/3/exec)).
|
as part of your program binary (during the call to [exec(3)](https://linux.die.net/man/3/exec)).
|
||||||
@ -144,7 +144,7 @@ but the specifications are clear enough: *don't rely on pointers to `const`
|
|||||||
values being consistent*. To be frank, caring about locations for `const` values
|
values being consistent*. To be frank, caring about locations for `const` values
|
||||||
is almost certainly a code smell.
|
is almost certainly a code smell.
|
||||||
|
|
||||||
## **static**
|
# **static**
|
||||||
|
|
||||||
Static variables are related to `const` variables, but take a slightly different approach.
|
Static variables are related to `const` variables, but take a slightly different approach.
|
||||||
When the compiler can guarantee that a *reference* is fixed for the life of a program,
|
When the compiler can guarantee that a *reference* is fixed for the life of a program,
|
||||||
|
Loading…
Reference in New Issue
Block a user