]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/vec/vec-push-pop.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / nomicon / src / vec / vec-push-pop.md
1 # Push and Pop
2
3 Alright. We can initialize. We can allocate. Let's actually implement some
4 functionality! Let's start with `push`. All it needs to do is check if we're
5 full to grow, unconditionally write to the next index, and then increment our
6 length.
7
8 To do the write we have to be careful not to evaluate the memory we want to write
9 to. At worst, it's truly uninitialized memory from the allocator. At best it's the
10 bits of some old value we popped off. Either way, we can't just index to the memory
11 and dereference it, because that will evaluate the memory as a valid instance of
12 T. Worse, `foo[idx] = x` will try to call `drop` on the old value of `foo[idx]`!
13
14 The correct way to do this is with `ptr::write`, which just blindly overwrites the
15 target address with the bits of the value we provide. No evaluation involved.
16
17 For `push`, if the old len (before push was called) is 0, then we want to write
18 to the 0th index. So we should offset by the old len.
19
20 <!-- ignore: simplified code -->
21 ```rust,ignore
22 pub fn push(&mut self, elem: T) {
23 if self.len == self.cap { self.grow(); }
24
25 unsafe {
26 ptr::write(self.ptr.as_ptr().add(self.len), elem);
27 }
28
29 // Can't fail, we'll OOM first.
30 self.len += 1;
31 }
32 ```
33
34 Easy! How about `pop`? Although this time the index we want to access is
35 initialized, Rust won't just let us dereference the location of memory to move
36 the value out, because that would leave the memory uninitialized! For this we
37 need `ptr::read`, which just copies out the bits from the target address and
38 interprets it as a value of type T. This will leave the memory at this address
39 logically uninitialized, even though there is in fact a perfectly good instance
40 of T there.
41
42 For `pop`, if the old len is 1, we want to read out of the 0th index. So we
43 should offset by the new len.
44
45 <!-- ignore: simplified code -->
46 ```rust,ignore
47 pub fn pop(&mut self) -> Option<T> {
48 if self.len == 0 {
49 None
50 } else {
51 self.len -= 1;
52 unsafe {
53 Some(ptr::read(self.ptr.as_ptr().add(self.len)))
54 }
55 }
56 }
57 ```