Setting array length without initializing/reallocating.
Steven Schveighoffer
schveiguy at gmail.com
Sun Dec 13 13:36:15 UTC 2020
On 12/11/20 7:53 PM, Jonathan Levi wrote:
> Wow, there went several hours of debugging.
>
> Increasing the length of a slice, by setting its length, will initialize
> the new elements and reallocate if necessary.
>
> I did not realize length was "smart", I guess I should have guessed.
>
> Anyway, to work around this, and probably also be more clear, create a
> new slice from the same pointer.
>
> `array = array.ptr[0..newLength];`
Lots of good responses to a mostly ambiguous message.
So let's go over some possibilities:
1. You want to *shrink* the array length. array = array[0 .. newLength]
works just fine. No reallocation, no initialization.
2. You want to *grow* the array length. array = array.ptr[0 ..
newLength] is incredibly wrong and dangerous. You should not do this.
3. You wish to have no allocation for growing an array beyond it's
already-allocated block. I only mention this because it could be implied
by your message, even though I'm pretty sure you don't mean this. This
is fantasy, and you should not do this. Memory corruption is something
you don't want to deal with. It's the reason why your chosen solution is
incorrect.
4. You wish to have no allocation for growing an array into it's ALREADY
allocated block. This is possible, and even possible without
reinitializing the new elements. In this context, your code is actually
OK, though like Sönke mentions, you should call assumeSafeAppend on the
array:
assert(newLength <= array.capacity); // ensure I am not growing beyond
the block.
array = array.ptr[0 .. newLength]; // yay, new data that is
uninitialized (mostly).
array.assumeSafeAppend(); // now the runtime is aware that I have taken
over that data for use.
Why is it important to call assumeSafeAppend? A few reasons:
1. The GC will run destructors on elements in an array only if they are
known to be used (in the case that your elements have destructors).
2. If you don't call it, appending to the original slice could overwrite
your data
3. If you try to append to the resulting array and there technically
would be space to fill inside the current block, the runtime will
needlessly reallocate if your array ends outside where it thinks it
should end.
Alternative to the assert, you could check for capacity and newLength to
be consistent, and if not, reallocate yourself.
-Steve
More information about the Digitalmars-d
mailing list