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?
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
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
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;
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
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.
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?
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 =3D new DeconstArrType!(TySub)[seq.length];
foreach (i, sub; seq)
result[i] =3D 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 =3D 0;
If I only do this :
inst.length =3D 0;
will all the instance items be automatically captured by garbage =
collector?
I believe the easiest would be to do inst =3D null;
"YY" <yyudhistira hotmail.com> wrote in message
news:ftj38l$19pr$1 digitalmars.com...
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?
If there are no other references to them, they will.
Apr 09 2008
↑ ↓ ← → Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Jarrett Billingsley wrote:
"YY" <yyudhistira hotmail.com> wrote in message
If I only do this :
inst.length = 0;
will all the instance items be automatically captured by garbage
collector?
If there are no other references to them, they will.
While the G would be well within its rights to collect them if no other
references exist, I'm pretty sure the current one doesn't.
The problem is that setting the length to 0 will only modify the array
reference, not the data that was in it. The memory block will still be
referenced and the current GC doesn't know what parts of a memory block
are actually in use.
The array contents cannot generally be cleared if the length of a
reference is set to 0 either, since there may be other references. So as
long as a pointer or array references that block of memory (and yes, a
0-length array can still reference a block of memory, namely the one
that will be used when '~=' is used on it) it won't be collected.
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.
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;
}
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):