|
Archives
D Programming
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
D.gnu
D
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
electronics
|
digitalmars.D.learn - going beyond your bounds
After a discussion on digitalmars.D I played with arrays a bit. Look at the
following code:
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
b ~= 11 ;
b[0] = 12 ;
Stdout(b).newline ;
Stdout(a).newline ;
The result is:
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
Which means that even though b was set only to a[0..10], after expanding b,
also has direct access to element a[10]. But
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
b.length = b.length+1 ;
b[0] = 11 ;
Stdout(b).newline ;
Stdout(a).newline ;
Gives
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
Now b is expanded in length, but a side effect is that a[10] is set to 0 (i.e.
initialized).
In the end, I think b can only see things that happen to a[10] after it
expanded, but not before. It seems there is no way for the following to work:
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
At this point, element a[10]=10 will never be visible to b. b can expand to it,
but by doing that, a[10] will be overwritten.
Is this on purpose? It could also be useful to have b.length=b.length+1 which
only initializes memory that has not been initialized before.
On Thu, 21 May 2009 04:51:16 -0400, MLT wrote:
After a discussion on digitalmars.D I played with arrays a bit. Look at the
following code:
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
b ~= 11 ;
b[0] = 12 ;
Stdout(b).newline ;
Stdout(a).newline ;
The result is:
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
Which means that even though b was set only to a[0..10], after expanding b,
also has direct access to element a[10]. But
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
b.length = b.length+1 ;
b[0] = 11 ;
Stdout(b).newline ;
Stdout(a).newline ;
Gives
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
[11, 2, 3, 4, 5, 6, 7, 8, 9, 0]
Now b is expanded in length, but a side effect is that a[10] is set to 0 (i.e.
initialized).
In the end, I think b can only see things that happen to a[10] after it
expanded, but not before. It seems there is no way for the following to work:
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a ;
a ~= 10 ;
At this point, element a[10]=10 will never be visible to b. b can expand to
it, but by doing that, a[10] will be overwritten.
Is this on purpose? It could also be useful to have b.length=b.length+1 which
only initializes memory that has not been initialized before.
Yes it is on purpose.
Here is what is happening ...
The contents of the array variable is actually a 2-element struct {addr,
length}. When you assign one array to another, that struct is what is
copied, not the array data itself.
int[] a = [1,2,3,4,5,6,7,8,9] ;
// Now 'a' contains {adr, 9}
int[] b = a ;
// Now 'b' contains {adr, 9}
a ~= 10 ;
// Now 'a' contains {adr, 10} -- The address doesn't change
-- because the buffer allocation
-- still enough room for another element.
b ~= 11 ;
// Now 'b' contains {adr, 10} -- The address doesn't change
-- because the buffer allocation
-- still enough room for another element
-- And that new element overwrote the '10'
-- appended to 'a'.
b[0] = 12 ;
// The element at address 'adr' is modified.
// As both 'a' and 'b' point to the same area
// it appears that updating 'b' changes 'a'.
The safe way to copy the data of an array is to do ...
int[] a = [1,2,3,4,5,6,7,8,9] ;
int[] b = a.dup ; // COPY a's data to to b.
a ~= 10 ;
b ~= 11 ;
b[0] = 12 ;
The result should now be:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[12, 2, 3, 4, 5, 6, 7, 8, 9, 11]
So remember, assigning one array to another is just creating an alias to
the original array. You end up with two arrays pointing to the same data
buffer.
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
Derek Parnell Wrote:
So remember, assigning one array to another is just creating an alias to
the original array. You end up with two arrays pointing to the same data
buffer.
Yes. My question relates to what happens when you go beyond the bounds
originally assigned.
Why does an extension of an array
b.length = b.length+1 ;
erase (initialize) the data that b extends to?
On Thu, 21 May 2009 05:37:59 -0400, MLT wrote:
Derek Parnell Wrote:
So remember, assigning one array to another is just creating an alias to
the original array. You end up with two arrays pointing to the same data
buffer.
Yes. My question relates to what happens when you go beyond the bounds
originally assigned.
Why does an extension of an array
b.length = b.length+1 ;
erase (initialize) the data that b extends to?
Because new elements are pre-initialized in D.
Just by increasing the length, you 'create' a new element (from the 'b'
point of view) so D initializes it.
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
Because new elements are pre-initialized in D.
Just by increasing the length, you 'create' a new element (from the 'b'
point of view) so D initializes it.
(We were talking about something like
int a[] = [1,2,3,4,5] ;
b = a ;
a ~= 6 ;
b.length = b.length+1;)
Hmmm... yes, that has some logic to it.
D does keep track of the actual array of integers that both a and b point to
and knows when to allocate new memory for the array. So in theory it could be
possible that when b.length increases, initialization only happens if this
memory is uninitialized.
On the other hand, I guess that if you get an array, say b, in a function, you
might rely on the fact that when you extend b.length, the area will be
initialized...
On Thu, 21 May 2009 05:58:04 -0400, MLT wrote:
Because new elements are pre-initialized in D.
Just by increasing the length, you 'create' a new element (from the 'b'
point of view) so D initializes it.
(We were talking about something like
int a[] = [1,2,3,4,5] ;
b = a ;
a ~= 6 ;
b.length = b.length+1;)
Hmmm... yes, that has some logic to it.
D does keep track of the actual array of integers that both a and b point to
Not really. The original data is a literal so it is supposed to be
unmodifiable (I think Linux enforces it but not sure).
and knows when to allocate new memory for the array.
It allocates new RAM when the current buffer allocation will not be large
enough to hold the new elements. When it does this, it allocates the new
buffer and copies the old data to it. This means that you cannot rely on
the alias 'feature' to work all the time.
For example ...
int[] a = [ some data ];
int[] b = a; // Ok, so both 'a' and 'b' point to the data now.
a ~= newone; // This can't fit in so an allocation occurs
// and the data copied, then 'a' is set to the
// the new buffer.
// BUT 'b' still points to the old buffer.
So in theory it could be possible that when b.length increases,
initialization only happens if this memory is uninitialized.
Theoreticaly yes, but it isn't going to happen.
On the other hand, I guess that if you get an array, say b,
in a function, you might rely on the fact that when you
extend b.length, the area will be initialized...
This is also a trap. If the function increases the length of the array
passed to it, there will be so initialization happening, but when the
function returns, the array variable passed to the function is unchanged.
Its length is not modified so the new initialized data is not part of the
array. This is because when you pass an array to a function, it's that
small struct that is passedon the stack, so changing that will not change
the argument's properties.
eg.
void func(int[] x)
{
x.length = x.length + 1;
}
int a[] = [1,2,3];
func(a);
writefln("%s", a) //--> [1,2,3] and not [1,2,3,0]
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
|
|