Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 08, 2008 Array of class intances | ||||
---|---|---|---|---|
| ||||
Suppose I have a class : class C { int a; int b; this(int a1, int b1) { a = a1; b = b1; } } And I want to make an array of class C instances : C[] inst; inst ~= new C(1,2); inst ~= new C(3,4); What happened if I make a copy of inst using dup? Are the values or the pointers are copied? C[] copyinst = inst.dup; When I tried to assert(inst.ptr == copyinst.ptr) it fails, which means it copies the contents. But when I do this : inst.a += 3; assert(inst.a != copyinst.a); It also fails. What's the best method to copy (clone) array of instances? |
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to YY | YY wrote: > Suppose I have a class : > > class C { > int a; > int b; > this(int a1, int b1) { > a = a1; > b = b1; > } > } > > And I want to make an array of class C instances : > > C[] inst; > inst ~= new C(1,2); > inst ~= new C(3,4); > > What happened if I make a copy of inst using dup? Are the values or the pointers are copied? > > C[] copyinst = inst.dup; > > When I tried to assert(inst.ptr == copyinst.ptr) it fails, which means it copies the contents. This assert tells you that the data pointer of the arrays is not equal, which means each array has it's own copy of the class references. But, it doesn't mean the class instances themselves have been duplicated. This shouldn't fail: assert(inst[0] == copyinst[0]); meaning the first item in each array is the same reference, you can see the value of the reference by doing this: writefln("%x", cast(void*)inst[0]); writefln("%x", cast(void*)copyinst[0]); > But when I do this : > > inst.a += 3; > assert(inst.a != copyinst.a); > > It also fails. That is because inst[0] and copyinst[0] both refer to the same class reference, therefore inst[0].a is the same variable as copyinst[0].a > What's the best method to copy (clone) array of instances? Add this method to your class C C dup() { return new C(a,b); } Then, instead of this: C[] copyinst = inst.dup; use: C[] copyinst; foreach(i; inst) copyinst ~= i.dup; Regan |
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | Regan Heath wrote:
> YY wrote:
>> Suppose I have a class :
>>
>> class C {
>> int a;
>> int b;
>> this(int a1, int b1) {
>> a = a1;
>> b = b1;
>> }
>> }
>>
>> And I want to make an array of class C instances :
>>
>> C[] inst;
>> inst ~= new C(1,2);
>> inst ~= new C(3,4);
>>
>> What happened if I make a copy of inst using dup? Are the values or the pointers are copied?
>>
>> C[] copyinst = inst.dup;
>>
>> When I tried to assert(inst.ptr == copyinst.ptr) it fails, which means it copies the contents.
>
> This assert tells you that the data pointer of the arrays is not equal, which means each array has it's own copy of the class references.
>
> But, it doesn't mean the class instances themselves have been duplicated.
>
> This shouldn't fail:
>
> assert(inst[0] == copyinst[0]);
The above assert should of course read:
assert(inst[0] is copyinst[0]);
Regan
|
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to YY | YY wrote: > Suppose I have a class : > > class C { > int a; > int b; > this(int a1, int b1) { > a = a1; > b = b1; > } > } > > And I want to make an array of class C instances : > > C[] inst; > inst ~= new C(1,2); > inst ~= new C(3,4); > > What happened if I make a copy of inst using dup? Are the values or the pointers are copied? The values are copied. But the values in this case are Objects, which are always pointers under the hood. So in the end pointers are copied by value ;) > C[] copyinst = inst.dup; > > When I tried to assert(inst.ptr == copyinst.ptr) it fails, which means it > copies the contents. 'inst.ptr == copyinst.ptr' compares the adressess of the arrays themselves, independent of their content. It means the arrays are stored in different place in memory, but the content can still be the same. Try this: inst[0] == copyinst[0] // true and this: &inst[0] == ©inst[0] // false > But when I do this : > > inst.a += 3; > assert(inst.a != copyinst.a); > > It also fails. > > What's the best method to copy (clone) array of instances? There is no standard way, perhaps somebody has written something? If haven't found a need for this myself yet, I prefer to use structs is these cases. You could implement an .dup or .clone method in your classes and create such a functions yourself, something like this (caution, not tested): T[] dup(T)(T[] a) { static if (is(typeof(T.dup))) { T[] result; result.length = a.length; foreach(i, val; a) result[i] = val.dup; return result; } else return a.dup; } |
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to lutger | lutger wrote:
> If haven't found a need for this myself yet, I prefer to use structs is these cases. You could implement an .dup or .clone method in your classes and create such a functions yourself, something like this (caution, not tested):
Sorry for my careless spelling, I'm a bit tired.
|
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Regan Heath | Regan Heath wrote:
> C[] copyinst;
> foreach(i; inst)
> copyinst ~= i.dup;
>
> Regan
this will give somewhat better performance because the ~= will allocate and copy a lot.
C[] copyinst;
copyinst.length = inst.length;
foreach(i,c; inst) copyinst[i] = c.dup;
if you want compact code and don't mind it being a bit confusing:
C[] copyinst = inst.dup;
foreach(inout i; inst) i = i.dup;
|
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to BCS | BCS: > C[] copyinst = inst.dup; > foreach(inout i; inst) i = i.dup; I suggest you to use ref instead of inout, I presume inout keyword will be removed. lutger: T[] dup(T)(T[] a) { static if (is(typeof(T.dup))) { T[] result; result.length = a.length; foreach(i, val; a) result[i] = val.dup; return result; } else return a.dup; } Nice. Something like this (untested, it may need debugging!) may be useful for nested arrays (IsArray is true for dynamic or static arrays and false in every other situation): template DeconstArrType(T) { // similar to std.bind.DynamicArrayType static if (IsArray!(T)) alias typeof(T[0])[] DeconstArrType; else alias T DeconstArrType; } DeconstArrType!(TySub)[] deepDup(TySub)(TySub[] seq) { static if (is(typeof(TySub.dup))) { auto result = new DeconstArrType!(TySub)[seq.length]; foreach (i, sub; seq) result[i] = deepDup(sub); return result; } else { return seq.dup; } } A generic deepcopy() function that works with everything (that needs the support of a special method in Object class too) may be useful. Bye, bearophile |
April 08, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote:
>
> Something like this may be useful for nested arrays
At one point I wrote a template that bundled up an array into a ubyte buffer in a way that could be shipped across a wire and rebuilt it on the other end. I didn't care how deep the arrays were nested.
|
April 09, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile |
> Something like this (untested, it may need debugging!) may be useful for nested arrays (IsArray is true for dynamic or static arrays and false in every other situation):
>
> template DeconstArrType(T) {
> // similar to std.bind.DynamicArrayType
> static if (IsArray!(T))
> alias typeof(T[0])[] DeconstArrType;
> else
> alias T DeconstArrType;
> }
>
> DeconstArrType!(TySub)[] deepDup(TySub)(TySub[] seq) {
> static if (is(typeof(TySub.dup))) {
> auto result = new DeconstArrType!(TySub)[seq.length];
> foreach (i, sub; seq)
> result[i] = deepDup(sub);
> return result;
> } else {
> return seq.dup;
> }
> }
>
> A generic deepcopy() function that works with everything (that needs the support of a special method in Object class too) may be useful.
>
Great, thanks for the hints. I have another question. Do I have to delete each and every member of the array? Like this :
foreach (ref i; inst) delete i;
inst.length = 0;
If I only do this :
inst.length = 0;
will all the instance items be automatically captured by garbage collector?
|
April 09, 2008 Re: Array of class intances | ||||
---|---|---|---|---|
| ||||
Posted in reply to YY | On Wed, 09 Apr 2008 20:52:05 +0200, YY <yyudhistira@hotmail.com> wrote:
>
>> Something like this (untested, it may need debugging!) may be useful for nested arrays (IsArray is true for dynamic or static arrays and false in every other situation):
>>
>> template DeconstArrType(T) {
>> // similar to std.bind.DynamicArrayType
>> static if (IsArray!(T))
>> alias typeof(T[0])[] DeconstArrType;
>> else
>> alias T DeconstArrType;
>> }
>>
>> DeconstArrType!(TySub)[] deepDup(TySub)(TySub[] seq) {
>> static if (is(typeof(TySub.dup))) {
>> auto result = new DeconstArrType!(TySub)[seq.length];
>> foreach (i, sub; seq)
>> result[i] = deepDup(sub);
>> return result;
>> } else {
>> return seq.dup;
>> }
>> }
>>
>> A generic deepcopy() function that works with everything (that needs the support of a special method in Object class too) may be useful.
>>
>
> Great, thanks for the hints. I have another question. Do I have to delete each and every member of the array? Like this :
>
> foreach (ref i; inst) delete i;
> inst.length = 0;
>
> If I only do this :
>
> inst.length = 0;
>
> will all the instance items be automatically captured by garbage collector?
I believe the easiest would be to do inst = null;
|
Copyright © 1999-2021 by the D Language Foundation