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