digitalmars.D - Pointers or copies?
- Orgoton (17/17) Dec 20 2006 I'm making a game and I have to keep track of the objects in the game, w...
- Chris Nicholson-Sauls (6/25) Dec 20 2006 Unless I am missing something, you shouldn't need to use pointers at all...
- Orgoton (17/17) Dec 20 2006 I haven't finished it yet. Well, each frame, the main engine will cycle ...
- Arlen Albert Keshabyan (5/7) Dec 20 2006 use operator '~=' to 'push_back' objects to an dynamic array :)
- Chris Nicholson-Sauls (5/32) Dec 20 2006 That's right. You could also use array concatenation (objts ~= target;)...
- Orgoton (14/14) Dec 20 2006 And when I want to remove the reference? Something like
- BCS (2/2) Dec 20 2006 I haven't used it but IIRC cashew has much of what you want.
- Chris Nicholson-Sauls (23/26) Dec 20 2006 It should. I was just trying to be nice and not go promoting it all ove...
- BCS (7/18) Dec 20 2006 It seems what he real wants is a set. How about use an AA:
- Chris Nicholson-Sauls (4/26) Dec 20 2006 That would be the ideal, if he is after a set. The void[T] did have its...
- Tom S (2/18) Dec 20 2006 Use 'is' instead of '=='. It will compare references.
- Frits van Bommel (10/26) Dec 20 2006 The compare will call opEquals, which will compare addresses by default....
- Frits van Bommel (3/6) Dec 20 2006 And what Tom said: if you want to enforce identity-comparison (or avoid
- BCS (7/21) Dec 20 2006 Take a look at foreach. If queue is an array, this will work:
- Tim Keating (6/9) Dec 21 2006 Little syntax nitpick -- that needs to be foreach(auto item; queue)
- Hasan Aljudy (4/16) Dec 22 2006 Actually, no.
- Arlen Albert Keshabyan (8/25) Dec 20 2006 RTM: use operator '&' to get its pointer.
- Hasan Aljudy (24/43) Dec 21 2006 In addition to what the others have said, here are some more tips:
- Chris Nicholson-Sauls (17/25) Dec 21 2006 It is "suboptimal" but not by /too/ much. Cashew uses C's memmove thank...
- Frits van Bommel (6/18) Dec 21 2006 Doesn't that move one element from beyond the end of the array?
- Chris Nicholson-Sauls (29/49) Dec 21 2006 Doesn't seem to. Illustrative program:
- Frits van Bommel (16/68) Dec 21 2006 How do you know it isn't touched? Just because it doesn't segfault
- Chris Nicholson-Sauls (4/74) Dec 22 2006 Actually, this is exactly what I have done. Its in the repository now.
I'm making a game and I have to keep track of the objects in the game, which inherit from a master object class called "objct". So I would make a class for "baddie", "player" and such. Now, to draw them I have to keep track of their existance, so, when one is created, it adds itself to the "frame queue" and removes itself when it is deleted. To keep track of them I created a "queue" class, which has a protected member called "objct *pters[]". It is an array of pointers so when I recieve a new actor for the queue, I increase the array size accordingly and on the next slot, just add it there. Simple. Now, the queue class has a method called "add" and "remove" both of them take as parameter "objct *target". To sum it up and finally tell you my question the objct has in it's constructor "framequeue.add(this);" and a correspondind "remove(this)". Apparently, "this" is not a pointer... as the compiler claims: "function queue.remoce (objct *target) does not match parameter types (objct)" and that "cannot implicitly convert expression (this) of type objct to objct*". So, does passing "this" create a copy of the object? How do I pass the pointer to the object to the queue? Any other solution?
Dec 20 2006
Orgoton wrote:I'm making a game and I have to keep track of the objects in the game, which inherit from a master object class called "objct". So I would make a class for "baddie", "player" and such. Now, to draw them I have to keep track of their existance, so, when one is created, it adds itself to the "frame queue" and removes itself when it is deleted. To keep track of them I created a "queue" class, which has a protected member called "objct *pters[]". It is an array of pointers so when I recieve a new actor for the queue, I increase the array size accordingly and on the next slot, just add it there. Simple. Now, the queue class has a method called "add" and "remove" both of them take as parameter "objct *target". To sum it up and finally tell you my question the objct has in it's constructor "framequeue.add(this);" and a correspondind "remove(this)". Apparently, "this" is not a pointer... as the compiler claims: "function queue.remoce (objct *target) does not match parameter types (objct)" and that "cannot implicitly convert expression (this) of type objct to objct*". So, does passing "this" create a copy of the object? How do I pass the pointer to the object to the queue? Any other solution?Unless I am missing something, you shouldn't need to use pointers at all. Object variables in D are referances to the actual object which lives off in space somewhere. (Where space happens to be the heap.) I'm also curious as to how this Queue class of yours is designed. It sounds like there ought to be an easier means. -- Chris Nicholson-Sauls
Dec 20 2006
I haven't finished it yet. Well, each frame, the main engine will cycle through all the pointers on the queue with something like for (i=0; i<queue.size; i++) queue.next().draw(); Or, to save up the callings queue.drawall() where all pointers would be called. I'm used to C++, sorry for the question about pointers and copies. That means I can just make something like objct objts[]; and use it just like a pointer... void add (in objct target) { objts[objts.lenght-1]=target; } (on objct) this {queue.add(this);} and it'l work just fine without creating copies of the objects? (and spare me of memory problems along the way :P)
Dec 20 2006
== Quote from Orgoton (orgoton mindless.com)'s articlevoid add (in objct target) { objts[objts.lenght-1]=target; }use operator '~=' to 'push_back' objects to an dynamic array :) e.g.: void add (in objct target) { objts ~= target; }
Dec 20 2006
Orgoton wrote:I haven't finished it yet. Well, each frame, the main engine will cycle through all the pointers on the queue with something like for (i=0; i<queue.size; i++) queue.next().draw(); Or, to save up the callings queue.drawall() where all pointers would be called. I'm used to C++, sorry for the question about pointers and copies. That means I can just make something like objct objts[]; and use it just like a pointer... void add (in objct target) { objts[objts.lenght-1]=target; } (on objct) this {queue.add(this);} and it'l work just fine without creating copies of the objects? (and spare me of memory problems along the way :P)That's right. You could also use array concatenation (objts ~= target;) if you aren't wanting to enforce a particular size. And since you plan to use this in a loop, it might be worth taking a look at foreach. -- Chris Nicholson-Sauls
Dec 20 2006
And when I want to remove the reference? Something like void remove(in object target) the_for: for (i=0; i<queue.length; i++) { if target==queue[i] { queue[i]=queue[$-1]; queue.length-=1; break the_for; } } the compare will work fine, right? I mean, in C++ it would just compare a 4 byte integer, how much data will D compare? hopefully, not he full object data ... ... ...
Dec 20 2006
I haven't used it but IIRC cashew has much of what you want. http://www.dsource.org/projects/cashew
Dec 20 2006
BCS wrote:I haven't used it but IIRC cashew has much of what you want. http://www.dsource.org/projects/cashewIt should. I was just trying to be nice and not go promoting it all over the place like I usually do. :) Also, as he said he is new to the language, I wasn't sure how he might feel about pseudo-members. Using Cashew, a Queue of type 'objct' as an array would look like: To add to the queue: To add multiple items: To remove from the queue: The only issue is if he wants the queue to be an exclusive set, in which case adding to the queue becomes: Or he could write a 'qpush' like so: -- Chris Nicholson-Sauls
Dec 20 2006
Chris Nicholson-Sauls wrote:The only issue is if he wants the queue to be an exclusive set, in which case adding to the queue becomes: Or he could write a 'qpush' like so: -- Chris Nicholson-SaulsIt seems what he real wants is a set. How about use an AA: bool[Objct] set; set[something] = true; // add something foreach(k,_;set) k.draw(); // work all set.remove(something); // to get rid of things To bad void[T] isn't allowed <g>.
Dec 20 2006
BCS wrote:Chris Nicholson-Sauls wrote:That would be the ideal, if he is after a set. The void[T] did have its shining moments. :) Alas. -- Chris Nicholson-SaulsThe only issue is if he wants the queue to be an exclusive set, in which case adding to the queue becomes: Or he could write a 'qpush' like so: -- Chris Nicholson-SaulsIt seems what he real wants is a set. How about use an AA: bool[Objct] set; set[something] = true; // add something foreach(k,_;set) k.draw(); // work all set.remove(something); // to get rid of things To bad void[T] isn't allowed <g>.
Dec 20 2006
Orgoton wrote:And when I want to remove the reference? Something like void remove(in object target) the_for: for (i=0; i<queue.length; i++) { if target==queue[i] { queue[i]=queue[$-1]; queue.length-=1; break the_for; } } the compare will work fine, right? I mean, in C++ it would just compare a 4 byte integer, how much data will D compare? hopefully, not he full object data ... ... ...Use 'is' instead of '=='. It will compare references.
Dec 20 2006
Orgoton wrote:And when I want to remove the reference? Something like void remove(in object target) the_for: for (i=0; i<queue.length; i++) { if target==queue[i] { queue[i]=queue[$-1]; queue.length-=1; break the_for; } } the compare will work fine, right? I mean, in C++ it would just compare a 4 byte integer, how much data will D compare? hopefully, not he full object data ... ... ...The compare will call opEquals, which will compare addresses by default. (Assuming the contents are class instances, not structs. Structs compare their contents by default) Unfortunately, decreasing the queue length will have to be done like this: queue.length = queue.length - 1; or: queue = queue[0 .. $-1]; because .length is a property, and as such op-assignments won't work, only direct assignment.
Dec 20 2006
Frits van Bommel wrote:The compare will call opEquals, which will compare addresses by default. (Assuming the contents are class instances, not structs. Structs compare their contents by default)And what Tom said: if you want to enforce identity-comparison (or avoid the virtual function-call) use 'is' instead of '=='.
Dec 20 2006
Orgoton wrote:I haven't finished it yet. Well, each frame, the main engine will cycle through all the pointers on the queue with something like for (i=0; i<queue.size; i++) queue.next().draw();Take a look at foreach. If queue is an array, this will work: foreach(item;queue) item.draw(); If it isn't an array, you can implement an opApply.That means I can just [...] objct objts[]; void add (in objct target) { objts[objts.lenght-1]=target; } and it'l work just fine without creating copies of the objects? (and spare me of memory problems along the way :P)yup. BTW this is the same thing objts[$-1]=target;
Dec 20 2006
In article <emceee$2s0a$1 digitaldaemon.com>, BCS pathilink.com says...Take a look at foreach. If queue is an array, this will work: foreach(item;queue) item.draw();Little syntax nitpick -- that needs to be foreach(auto item; queue) item.draw(), I believe. Normally I wouldn't fuss, but the OP did say he was new to the language :) TK
Dec 21 2006
Tim Keating wrote:In article <emceee$2s0a$1 digitaldaemon.com>, BCS pathilink.com says...Actually, no. foreach( item; list ) { .. } works automagically :)Take a look at foreach. If queue is an array, this will work: foreach(item;queue) item.draw();Little syntax nitpick -- that needs to be foreach(auto item; queue) item.draw(), I believe. Normally I wouldn't fuss, but the OP did say he was new to the language :) TK
Dec 22 2006
== Quote from Orgoton (orgoton mindless.com)'s articleI'm making a game and I have to keep track of the objects in the game, which inherit from a master object class called "objct". So I would make a class for "baddie", "player" and such. Now, to draw them I have to keep track of their existance, so, when one is created, it adds itself to the "frame queue" and removes itself when it is deleted. To keep track of them I created a "queue" class, which has a protected member called "objct *pters[]". It is an array of pointers so when I recieve a new actor for the queue, I increase the array size accordingly and on the next slot, just add it there. Simple. Now, the queue class has a method called "add" and "remove" both of them take as parameter "objct *target". To sum it up and finally tell you my question the objct has in it's constructor "framequeue.add(this);" and a correspondind "remove(this)". Apparently, "this" is not a pointer... as the compiler claims: "function queue.remoce (objct *target) does not match parameter types (objct)" and that "cannot implicitly convert expression (this) of type objct to objct*". So, does passing "this" create a copy of the object? How do I pass the pointer to the object to the queue? Any other solution?RTM: use operator '&' to get its pointer. e.g. framequeue.add(&this); Anyway, I recommend you to use all objects by reference, no pointers at all. e.g.: object[] framequeue; framequeue ~= this; framequeue ~= another_object;
Dec 20 2006
In addition to what the others have said, here are some more tips: * All D class inherit from Object by default. So, if your "object" class doesn't do anything special, you can ditch it, and use the standard Object class. * You can iterate over an array using foreach: Object[] objs .. foreach( Object object; objs ) { //do something } even better, foreach has magical type deduction, so you don't have to say "foreach Object object", just say: foreach( object; object_list ) { .. } The compiler will automatically deduce the type of "object" based on "object_list". * You can remove an element from the array using a slicing trick: void remove( Object[] array, int i ) { array = array[0..i] ~ array[i+1..$]; } I haven't tested this but it should work, although I suspect it maybe suboptimal. The $ inside the slice refers to array.length. Orgoton wrote:I'm making a game and I have to keep track of the objects in the game, which inherit from a master object class called "objct". So I would make a class for "baddie", "player" and such. Now, to draw them I have to keep track of their existance, so, when one is created, it adds itself to the "frame queue" and removes itself when it is deleted. To keep track of them I created a "queue" class, which has a protected member called "objct *pters[]". It is an array of pointers so when I recieve a new actor for the queue, I increase the array size accordingly and on the next slot, just add it there. Simple. Now, the queue class has a method called "add" and "remove" both of them take as parameter "objct *target". To sum it up and finally tell you my question the objct has in it's constructor "framequeue.add(this);" and a correspondind "remove(this)". Apparently, "this" is not a pointer... as the compiler claims: "function queue.remoce (objct *target) does not match parameter types (objct)" and that "cannot implicitly convert expression (this) of type objct to objct*". So, does passing "this" create a copy of the object? How do I pass the pointer to the object to the queue? Any other solution?
Dec 21 2006
Hasan Aljudy wrote:* You can remove an element from the array using a slicing trick: void remove( Object[] array, int i ) { array = array[0..i] ~ array[i+1..$]; } I haven't tested this but it should work, although I suspect it maybe suboptimal. The $ inside the slice refers to array.length.It is "suboptimal" but not by /too/ much. Cashew uses C's memmove thanks to a couple of other D'ers who proved the performance differences. (I only mention it because he specifically said he's writing games, and performance would therefore be important.) In case he doesn't want all of Cashew, the implementation of .drop follows: void drop (T) (inout T[] haystack, size_t index) in { assert(index < haystack.length, ".drop() called with index greater than array length"); } body { if (index != haystack.length - 1) { memmove(&(haystack[index]), &(haystack[index + 1]), T.sizeof * (haystack.length - index)); } haystack.length = haystack.length - 1; } -- Chris Nicholson-Sauls
Dec 21 2006
Chris Nicholson-Sauls wrote:void drop (T) (inout T[] haystack, size_t index) in { assert(index < haystack.length, ".drop() called with index greater than array length"); } body { if (index != haystack.length - 1) { memmove(&(haystack[index]), &(haystack[index + 1]), T.sizeof * (haystack.length - index)); } haystack.length = haystack.length - 1; }Doesn't that move one element from beyond the end of the array? Array [0, 1, 2], drop element at index 1: memmove(&(array[1]), &(array[2]), int.sizeof * (3-1)); Moves 2 elements, starting at the 3rd element (element at index 2) of a 3-element array...
Dec 21 2006
Frits van Bommel wrote:Chris Nicholson-Sauls wrote:Doesn't seem to. Illustrative program: For me this output: foo.alpha == [0,1,2] foo.beta == [3,4,5] foo.alpha == [0,2] foo.beta == [3,4,5] Which seems to imply the data after alpha isn't being touched. That said, I'll try changing it anyhow. Just in case. -- Chris Nicholson-Saulsvoid drop (T) (inout T[] haystack, size_t index) in { assert(index < haystack.length, ".drop() called with index greater than array length"); } body { if (index != haystack.length - 1) { memmove(&(haystack[index]), &(haystack[index + 1]), T.sizeof * (haystack.length - index)); } haystack.length = haystack.length - 1; }Doesn't that move one element from beyond the end of the array? Array [0, 1, 2], drop element at index 1: memmove(&(array[1]), &(array[2]), int.sizeof * (3-1)); Moves 2 elements, starting at the 3rd element (element at index 2) of a 3-element array...
Dec 21 2006
Chris Nicholson-Sauls wrote:Frits van Bommel wrote:How do you know it isn't touched? Just because it doesn't segfault doesn't mean it isn't accessing beyond array bounds... In fact, as long as the int after alpha is readable (i.e. the memory is mapped) you won't see a difference with that code. You'd probably see a difference if you kept a copy of alpha around and wrote that to output as well, though. (since the length of the copy doesn't get adjusted) In fact, I just tried that and the last element of alpha is overwritten by the first element of beta. This shouldn't happen if memmove() is called with the correct parameters. Another way to see this without keeping references to arrays being modified (which is arguably bad style) is the following: Replace the last argument of the memmove call with 'T.sizeof * (haystack.length - index - 1)' and notice your code above gives the exact same result...Chris Nicholson-Sauls wrote:Doesn't seem to. Illustrative program: For me this output: foo.alpha == [0,1,2] foo.beta == [3,4,5] foo.alpha == [0,2] foo.beta == [3,4,5] Which seems to imply the data after alpha isn't being touched. That said, I'll try changing it anyhow. Just in case.void drop (T) (inout T[] haystack, size_t index) in { assert(index < haystack.length, ".drop() called with index greater than array length"); } body { if (index != haystack.length - 1) { memmove(&(haystack[index]), &(haystack[index + 1]), T.sizeof * (haystack.length - index)); } haystack.length = haystack.length - 1; }Doesn't that move one element from beyond the end of the array? Array [0, 1, 2], drop element at index 1: memmove(&(array[1]), &(array[2]), int.sizeof * (3-1)); Moves 2 elements, starting at the 3rd element (element at index 2) of a 3-element array...
Dec 21 2006
Frits van Bommel wrote:Chris Nicholson-Sauls wrote:Well, there we are then. :)Frits van Bommel wrote:How do you know it isn't touched? Just because it doesn't segfault doesn't mean it isn't accessing beyond array bounds... In fact, as long as the int after alpha is readable (i.e. the memory is mapped) you won't see a difference with that code. You'd probably see a difference if you kept a copy of alpha around and wrote that to output as well, though. (since the length of the copy doesn't get adjusted) In fact, I just tried that and the last element of alpha is overwritten by the first element of beta. This shouldn't happen if memmove() is called with the correct parameters.Chris Nicholson-Sauls wrote:Doesn't seem to. Illustrative program: For me this output: foo.alpha == [0,1,2] foo.beta == [3,4,5] foo.alpha == [0,2] foo.beta == [3,4,5] Which seems to imply the data after alpha isn't being touched. That said, I'll try changing it anyhow. Just in case.void drop (T) (inout T[] haystack, size_t index) in { assert(index < haystack.length, ".drop() called with index greater than array length"); } body { if (index != haystack.length - 1) { memmove(&(haystack[index]), &(haystack[index + 1]), T.sizeof * (haystack.length - index)); } haystack.length = haystack.length - 1; }Doesn't that move one element from beyond the end of the array? Array [0, 1, 2], drop element at index 1: memmove(&(array[1]), &(array[2]), int.sizeof * (3-1)); Moves 2 elements, starting at the 3rd element (element at index 2) of a 3-element array...Another way to see this without keeping references to arrays being modified (which is arguably bad style) is the following: Replace the last argument of the memmove call with 'T.sizeof * (haystack.length - index - 1)' and notice your code above gives the exact same result...Actually, this is exactly what I have done. Its in the repository now. -- Chris Nicholson-Sauls
Dec 22 2006