I have some code where I iterate an array of structs, capturing a pointer to the element. Each element contains a start and length field. The length is used to increase the value of an accumulator.
In order to accomplish this, I have a few options:
- store the previous iteration’s accumulator value then bump it immediately
- use the accumulator value directly then bump it at the end of the loop
- use
deferto accomplish option 2 while maintaining the locality of statements in option 1
Here’s how those play out:
Option 1
var acc: usize = 0;
for (items) |*item| {
const pos = acc;
acc += item.len;
// do stuff with pos
}
Option 2
var acc: usize = 0;
for (items) |*item| {
// do stuff with acc
acc += item.len;
}
Option 3
var acc: usize = 0;
for (items) |*item| {
defer acc += item.len;
// do stuff with acc
}
Stylistically, I prefer option 3 but I discovered a not-so-obvious problem with this. Option 3 was segfaulting for me, and the best guess at why is because the pointer no longer referenced valid memory (something to do with this “at scope exit”). I don’t know why, though.
To fix this, I store a copy of the dereferenced value in the loop and use that instead of the capture:
var acc: usize = 0;
for (items) |*item| {
const item_copy = item.*;
defer acc += item_copy.len;
// do stuff with acc
}
So, is this a skill issue resulting from a misunderstanding of defer? Or is this a possible footgun? The langref says this about defer:
Executes an expression unconditionally at scope exit.
To me, this is a bit vague. What does “at scope exit” mean (in a temporal sense)?
EDIT: The segfault was occurring in a test.