Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
January 03, 2009 Struct copy, how? | ||||
---|---|---|---|---|
| ||||
(D 1.0) After some problems with my program I found where my problems arose. In my mini example: A function that is supposed to create a new bear from 2 exisiting bears ends up altering the original bears. I suspect it has to do with the line ' Bear newBear = bear1;', in that it doesn't copy the contents of the struct. Is there a way to copy a struct without resorting to iterating over all its elements manually? module main; import std.stdio; struct Claw { int n; } struct Bear { Claw[] claw; } struct StoredBears { Bear[] bear; } StoredBears storedBears; Bear mixBears(Bear bear1, Bear bear2) { Bear newBear = bear1; writefln(storedBears.bear[0].claw[0].n); writefln(storedBears.bear[1].claw[0].n); writefln(bear1.claw[0].n); writefln(bear2.claw[0].n); writefln(newBear.claw[0].n); writefln(); newBear.claw[0].n = bear2.claw[0].n; writefln(storedBears.bear[0].claw[0].n); writefln(storedBears.bear[1].claw[0].n); writefln(bear1.claw[0].n); writefln(bear2.claw[0].n); writefln(newBear.claw[0].n); return newBear; } void main() { //create 2 bears and put them in the storedBears struct created above Bear storedBear1; storedBear1.claw.length = 1; storedBear1.claw[0].n = 1; storedBears.bear ~= storedBear1; Bear storedBear2; storedBear2.claw.length = 1; storedBear2.claw[0].n = 2; storedBears.bear ~= storedBear2; //create a new bear from the 2 bears Bear newBear = mixBears(storedBears.bear[0],storedBears.bear[1]); } |
January 03, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to nobody | Reply to nobody,
> (D 1.0)
>
> After some problems with my program I found where my problems arose.
>
> In my mini example: A function that is supposed to create a new bear
> from 2
> exisiting bears ends up altering the original bears.
> I suspect it has to do with the line ' Bear newBear = bear1;', in that
> it
> doesn't copy the contents of the struct.
> Is there a way to copy a struct without resorting to iterating over
> all its
> elements manually?
I think you almost spotted the cause. Bear contains an array (a reference type) of Claws. When you copy it you get a new struct with a copy of that array (again a reference). Because that array is a reference type it still referees to that same set of Claws. You can fix this by copying/duping the array
Bear newBear = bear1;
newBear.claw = bear1.claw.dup;
IIRC struct now have an opAssign that can burry this in the struct code rather than the client code.
However this still has a few problems: 1, if claw contains a reference type you will now have 2 Claws that refer to the same thing and 2, you need to maintain opAssign to be sure that it copies all members.
One way to attack both of these would be to use a template to build a generic deep copy that uses compile time refection to copy all the members, duping arrays of PODS, copying basic types and recursively deep copying reference types and arrays of them.
|
January 03, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to BCS | "BCS" <ao@pathlink.com> wrote in message news:78ccfa2d380248cb3b2f9739eb46@news.digitalmars.com... > Reply to nobody, > >> (D 1.0) >> >> After some problems with my program I found where my problems arose. >> >> In my mini example: A function that is supposed to create a new bear >> from 2 >> exisiting bears ends up altering the original bears. >> I suspect it has to do with the line ' Bear newBear = bear1;', in that >> it >> doesn't copy the contents of the struct. >> Is there a way to copy a struct without resorting to iterating over >> all its >> elements manually? > > I think you almost spotted the cause. Bear contains an array (a reference type) of Claws. When you copy it you get a new struct with a copy of that array (again a reference). Because that array is a reference type it still referees to that same set of Claws. You can fix this by copying/duping the array Oh I see. I find it a bit odd that it's copied in this manner, but I bet there's good reasons for it. Totally unexpected to me though :) > > Bear newBear = bear1; > newBear.claw = bear1.claw.dup; > > IIRC struct now have an opAssign that can burry this in the struct code rather than the client code. Is opAssign available in D1.0? > However this still has a few problems: 1, if claw contains a reference type you will now have 2 Claws that refer to the same thing and 2, you need to maintain opAssign to be sure that it copies all members. > > One way to attack both of these would be to use a template to build a generic deep copy that uses compile time refection to copy all the members, duping arrays of PODS, copying basic types and recursively deep copying reference types and arrays of them. > > Guess I'll do that. Thanks for the help! |
January 03, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to nobody | nobody: BCS: > > However this still has a few problems: 1, if claw contains a reference type you will now have 2 Claws that refer to the same thing and 2, you need to maintain opAssign to be sure that it copies all members. > > > > One way to attack both of these would be to use a template to build a generic deep copy that uses compile time refection to copy all the members, duping arrays of PODS, copying basic types and recursively deep copying reference types and arrays of them. > Guess I'll do that. > Thanks for the help! If you create a generic deep copy I may find it useful. Bye, bearophile |
January 04, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | "bearophile" <bearophileHUGS@lycos.com> wrote in message news:gjn7s1$1vk4$1@digitalmars.com... > nobody: > BCS: >> > However this still has a few problems: 1, if claw contains a reference type you will now have 2 Claws that refer to the same thing and 2, you need to maintain opAssign to be sure that it copies all members. >> > >> > One way to attack both of these would be to use a template to build a >> > generic deep copy that uses compile time refection to copy all the >> > members, duping arrays of PODS, copying basic types and recursively >> > deep >> > copying reference types and arrays of them. > >> Guess I'll do that. >> Thanks for the help! > > If you create a generic deep copy I may find it useful. > > Bye, > bearophile Heh, unfortunately I wouldn't even know where to begin in order to make something like that. |
January 04, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to nobody |
nobody wrote:
> "bearophile" <bearophileHUGS@lycos.com> wrote in message news:gjn7s1$1vk4$1@digitalmars.com...
>> nobody:
>> BCS:
>>>> However this still has a few problems: 1, if claw contains a reference
>>>> type you will now have 2 Claws that refer to the same thing and 2, you
>>>> need to maintain opAssign to be sure that it copies all members.
>>>>
>>>> One way to attack both of these would be to use a template to build a
>>>> generic deep copy that uses compile time refection to copy all the
>>>> members, duping arrays of PODS, copying basic types and recursively deep
>>>> copying reference types and arrays of them.
>>> Guess I'll do that.
>>> Thanks for the help!
>> If you create a generic deep copy I may find it useful.
>>
>> Bye,
>> bearophile
>
> Heh, unfortunately I wouldn't even know where to begin in order to make something like that.
Off the top of my head, it wouldn't be terribly hard.
What you would need is a global 'ddup' (deep-dup) function. The generic case would look something like:
T ddup(T)(ref T value)
{
T result;
foreach( i,f ; value.tupleof )
result.tupleof[i] = ddup(f);
return result;
}
You'd then have to use either specialisation or lots of static if's to account for reference types, allocating new memory as necessary.
Can't see any particular reason why you couldn't do it...
-- Daniel
|
January 04, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote:
> Off the top of my head, it wouldn't be terribly hard.
>
> What you would need is a global 'ddup' (deep-dup) function. The generic case would look something like:
>
> T ddup(T)(ref T value)
> {
> T result;
> foreach( i,f ; value.tupleof )
> result.tupleof[i] = ddup(f);
> return result;
> }
>
> You'd then have to use either specialisation or lots of static if's to account for reference types, allocating new memory as necessary.
>
> Can't see any particular reason why you couldn't do it...
>
> -- Daniel
You want ddup to be polymorphic. Let's say you have a class with no default constructor, or a class that starts listening on a socket with some default local port -- in the first case, you couldn't ddup it without some ugliness; in the second, you could ddup it, but you'd get an exception because the port's already in use.
It would suffice to have an IClonable interface, and to check structs for a ddup property.
|
January 05, 2009 Re: Struct copy, how? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright |
Christopher Wright wrote:
> Daniel Keep wrote:
>> Off the top of my head, it wouldn't be terribly hard.
>>
>> What you would need is a global 'ddup' (deep-dup) function. The generic case would look something like:
>>
>> T ddup(T)(ref T value)
>> {
>> T result;
>> foreach( i,f ; value.tupleof )
>> result.tupleof[i] = ddup(f);
>> return result;
>> }
>>
>> You'd then have to use either specialisation or lots of static if's to account for reference types, allocating new memory as necessary.
>>
>> Can't see any particular reason why you couldn't do it...
>>
>> -- Daniel
>
> You want ddup to be polymorphic. Let's say you have a class with no default constructor, or a class that starts listening on a socket with some default local port -- in the first case, you couldn't ddup it without some ugliness; in the second, you could ddup it, but you'd get an exception because the port's already in use.
>
> It would suffice to have an IClonable interface, and to check structs for a ddup property.
Obviously, you'd need to have the class support it itself; but the original question was in regards to a struct deep copy. :P
For reference, I've written a generic serialise/deserialise pair of functions that do, more or less, the same thing, so it can be done.
-- Daniel
|
Copyright © 1999-2021 by the D Language Foundation