Array slice length confusion

Steven Schveighoffer schveiguy at yahoo.com
Wed Jul 8 21:15:59 PDT 2009


On Wed, 08 Jul 2009 23:09:52 -0400, Tim Matthews <tim.matthews7 at gmail.com>  
wrote:

> Steven Schveighoffer wrote:
>> On Wed, 08 Jul 2009 02:48:31 -0400, Tim Matthews  
>> <tim.matthews7 at gmail.com> wrote:
>>
>>> Was this a design choice, bug, undefined behavior, etc...?
>>  design choice.
>>  A slice *is* an array in the current design.  Increasing the length  
>> may or may not make a copy of it.  An array slice doesn't know it was  
>> originally part of another array (i.e. there are no references back to  
>> the original array) so how would it know that there is data around it?   
>> The only exception is appending to a prefix slice.  If a slice starts  
>> at the front of an allocated array, the runtime cannot tell that it was  
>> not the original array, so it clobbers data that was in the original  
>> array:
>>  char[] str = "blah".dup;
>> char[] sl = str[0..1];
>> sl ~= "r";
>> assert(str == "brah");
>>  BTW, all of this is defined behavior, see  
>> http://www.digitalmars.com/d/2.0/arrays.html#resize
>>  -Steve
>
> I thought a slice would behave slighty different due to some sort of  
> meta data that is a separate area of memory so it doesn't effect D's abi.
>
> Anyway if anyone gets here through a search engine the correct code  
> assuming you can guarantee it is a slice and that doesn't go out of  
> bounds. It is a systems language after all :)
>
> module test;
>
> import std.stdio;
>
> void resizeView(T)(ref T[] slice, size_t newLength)
> {
>      (cast(size_t*)(&slice))[0] = newLength;
> }
>
> void main()
> {
>      char[5] a = "hello";
>      char[] b = a[1..3];
>      writeln(a); //(hello)
>      writeln(b); //(el)
>      resizeView(b, b.length+1);
>      writeln(a); //(hello)
>      writeln(b); //(ell)
> }

This is really not a good idea.  You've removed one of the core features  
of the array -- memory safety.  Doing this is just asking for memory  
corruption.  You should either re-slice the original array, or create a  
type that has a reference to the original array so it can be resliced:

start with:

struct TimSlice(T)
{
   T[] slice;
   alias slice this;
   T[] srcArray;

   // override length property
   size_t length() {return slice.length;}
   void length(size_t) {/* use srcArray here to re-slice */}
}

This is assuming you are using D2, of course.  With D1, it's more  
difficult.

-Steve


More information about the Digitalmars-d-learn mailing list