@@ -124,21 +124,65 @@ special annotation here, it’s the default thing that Rust does.
124124## The details
125125
126126The reason that we cannot use a binding after we’ve moved it is subtle, but
127- important. When we write code like this:
127+ important.
128+
129+ When we write code like this:
130+
131+ ``` rust
132+ let x = 10 ;
133+ ```
134+
135+ Rust allocates memory for an integer [ i32] on the [ stack] [ sh ] , copies the bit
136+ pattern representing the value of 10 to the allocated memory and binds the
137+ variable name x to this memory region for future reference.
138+
139+ Now consider the following code fragment:
128140
129141``` rust
130142let v = vec! [1 , 2 , 3 ];
131143
132- let v2 = v ;
144+ let mut v2 = v ;
145+ ```
146+
147+ The first line allocates memory for the vector object ` v ` on the stack like
148+ it does for ` x ` above. But in addition to that it also allocates some memory
149+ on the [ heap] [ sh ] for the actual data (` [1, 2, 3] ` ). Rust copies the address
150+ of this heap allocation to an internal pointer, which is part of the vector
151+ object placed on the stack (let's call it the data pointer).
152+
153+ It is worth pointing out (even at the risk of stating the obvious) that the
154+ vector object and its data live in separate memory regions instead of being a
155+ single contiguous memory allocation (due to reasons we will not go into at
156+ this point of time). These two parts of the vector (the one on the stack and
157+ one on the heap) must agree with each other at all times with regards to
158+ things like the length, capacity etc.
159+
160+ When we move ` v ` to ` v2 ` , rust actually does a bitwise copy of the vector
161+ object ` v ` into the stack allocation represented by ` v2 ` . This shallow copy
162+ does not create a copy of the heap allocation containing the actual data.
163+ Which means that there would be two pointers to the contents of the vector
164+ both pointing to the same memory allocation on the heap. It would violate
165+ Rust’s safety guarantees by introducing a data race if one could access both
166+ ` v ` and ` v2 ` at the same time.
167+
168+ For example if we truncated the vector to just two elements through ` v2 ` :
169+
170+ ``` rust
171+ # let v = vec! [1 , 2 , 3 ];
172+ # let mut v2 = v ;
173+ v2 . truncate (2 );
133174```
134175
135- The first line allocates memory for the vector object, ` v ` , and for the data it
136- contains. The vector object is stored on the [ stack] [ sh ] and contains a pointer
137- to the content (` [1, 2, 3] ` ) stored on the [ heap] [ sh ] . When we move ` v ` to ` v2 ` ,
138- it creates a copy of that pointer, for ` v2 ` . Which means that there would be two
139- pointers to the content of the vector on the heap. It would violate Rust’s
140- safety guarantees by introducing a data race. Therefore, Rust forbids using ` v `
141- after we’ve done the move.
176+ and ` v1 ` were still accessible we'd end up with an invalid vector since ` v1 `
177+ would not know that the heap data has been truncated. Now, the part of the
178+ vector ` v1 ` on the stack does not agree with the corresponding part on the
179+ heap. ` v1 ` still thinks there are three elements in the vector and will
180+ happily let us access the non existent element ` v1[2] ` but as you might
181+ already know this is a recipe for disaster. Especially because it might lead
182+ to a segmentation fault or worse allow an unauthorized user to read from
183+ memory to which they don't have access.
184+
185+ This is why Rust forbids using ` v ` after we’ve done the move.
142186
143187[ sh ] : the-stack-and-the-heap.html
144188
0 commit comments