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