on structs by reference

Mike Parker via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Nov 14 03:48:41 PST 2015


On Saturday, 14 November 2015 at 10:46:57 UTC, Alex wrote:
> Hi everybody,
> I have the following question about "by reference" behavior 
> related to structs.
>
> I have a struct, say S, which contains a member of reference 
> type
> struct S
> {
>     int[] member;
> }
>
> and I have a main, for testing:
>
> void main()
> {
> 	S s; // = new S();
> 	s.arr = [1,2,3];
> 	writeln(s.arr); //first
> 	
> 	S t; // = new S();
> 	t = s;
> 	writeln(t.arr); //second
> 	
> 	s.arr ~= 4;
> 	writeln(s.arr); //third
> 	writeln(t.arr);
> }
>
> So, I create a first var of type S, then the second and copied 
> the first into the second. The behavior is like intended, the 
> array inside the struct is copied. But this is a deep copy, as 
> the third block shows. If I change the array in the 's' var, it 
> is not propagated into the 't' var.

Actually, no, it isn't a deep copy. You seem to be missing the 
fundamentals of how slices (dynamic arrays) work in D. Read 
Steven's article at [1] for the details. Essentially, you can 
think of an array in D like this:

struct Array(T) {
     size_t length;
     T* ptr;
}

When you assign s to t, this is what is being copied... *not* the 
contents of the array. Both arrays will still point into the same 
memory. Add these two lines immediately after t = s:

writeln(s.arr.ptr);
writeln(t.arr.ptr);

You will see they print the same address. If you try something 
like this:

s.arr[0] = 100;

You will see the change reflected in both s and t. Add the same 
two calls to writeln after s ~= 4 and you will see the addresses 
are now different. Steven's article explains what's going on.

>
> What I want to do is: the propagation of changes to all vars, 
> which are copies of the first one.
>
> The idea which works:
> change the definition of S into class and add 'new' on defining 
> the vars.
> Then, the example shows the desired behavior.

For what you want to do, this is probably your best option. The 
other is work with S by pointer, but then you can still use S as 
a value type. Structs are value types, classes are reference 
types. If you never want the behavior of a value type for a given 
type, use a class.

>
> The second idea: implement a postblit into the struct S.
> The problem hereby is, how to reference the unique var more 
> then once? How does the postblit looks like? Is it simple a 
> @disable this(this)? But then, I couldn't copy the vars at 
> all... but indeed I don't want to copy them, I rather would 
> like to reference them, if they are intended to mirror the same 
> internal value. Is this idea possible at all?

postblit is often used to make sure you get a deep copy of an 
array or any reference types:

struct S
{
     int[] arr;
     this(this) {
         arr = arr.dup;
     }
}


[1] http://dlang.org/d-array-article.html


More information about the Digitalmars-d-learn mailing list