Skip to main content
gamedev.net
🔒 Locked

Dynamic Allocation in Game Programming

Started by Noegddgeon 12 replies 1.8k views
Original Post
Noegddgeon
Noegddgeon
Hello, everybody.

My studies in C++ have brought me to the subject of pointers and, more specifically, dynamic memory allocation. I understand that, given the declaration of a pointer beforehand, it can be used to dynamically allocate memory in items like arrays and such. I also understand this can happen with objects.

However, let's pretend I want to write a game, and in this game, I have enemies that randomly spawn with their own attributes depending on whether certain conditions have been met, and their numbers cannot be predefined. In this case, I would desirably use dynamic memory allocation. But how could I dynamically allocate a virtually unlimited number of these creatures, beings, anything? (I'm going to say I'd use a class for these creatures, of course, so that way all of their information is modulated in a sense when they are created as objects dynamically.)

Any help, tips, suggestions, clarifications, etc. would be appreciated. I've programmed things like Pong and a space shooter-type little game, so I'm not completely in the dark, but pointers are a little bit new to me. Thank you all for your time and help :]

Colton
Nypyren
Nypyren
Container Classes

For example, std::vector.

Obviously this is limited by available process memory, but on most PCs that will be a LOT of data.
Aardvajk
Aardvajk
Common approach would be to use a std::vector of pointers to your entities. You need to delete them when you are done though:

class Entity{// blah};class Monster : public Entity{};class NPC : public Entity{};std::vector<Entity*> Entities;void Spawn(){    Entities.push_back(new Monster());    Entities.push_back(new NPC());    // etc}void CleanUp(){    for(std::vector<Entity*>::iterator I=Entities.begin();I!=Entities.end();++I)        {        delete *I;        }}


You might like to look into boost::ptr_vector instead.
Noegddgeon
Noegddgeon
Oh wow, that was actually not as difficult as I was thinking it would be. Having just used vectors, it especially makes sense to me. Thanks you guys for the info.... and the brain fodder ;]
21st Century Moose
21st Century Moose
std::vector is nice enough for simple uses, but be aware that it's not a silver bullet. Specific problems you might encounter include the possibility that it will need to reallocate the entire array (and it is a bog standard array underneath) and the fact that doing such a reallocation will invalidate all other references you may have elsewhere in your code to both the vector and to objects contained in the vector.

Reference: http://www.cplusplus.com/reference/stl/vector/push_back/

It's important that you are aware of these before you use it, otherwise you may experience strange behaviour in your program without knowing where it's coming from.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
rip-off
rip-off
Quote:

Specific problems you might encounter include the possibility that it will need to reallocate the entire array (and it is a bog standard array underneath) and the fact that doing such a reallocation will invalidate all other references you may have elsewhere in your code to both the vector and to objects contained in the vector.

A reallocation will never invalidate references to the vector itself, but pointers or references to the objects contained and iterators will be invalidated. In the case the vector stores pointers, then only pointer-to-pointer or reference-to-pointers will be invalidated, not pointers to the objects themselves (the vector will not and cannot move the pointed-to objects).

While it is good advice to keep in mind, I'd hardly say that this disqualifies vector from non "simple uses". It practically is a silver bullet, once you understand how to use it correctly. A great number of bugs and performance issues are solved by using a Standard C++ Library container rather than some hand rolled alternative.

Quote:

It's important that you are aware of these before you use it, otherwise you may experience strange behaviour in your program without knowing where it's coming from.

Good advice: read the documentation before doing non-trivial things. Somewhere beginners frequently mess up is modifying the vector structurally while iterating over it. Naive loops to remove elements are often written in a way that will cause iterators to become invalid, as well as running in O(n2). Research the remove/erase idiom for the right way to do this.

@OP You might find these videos on the Standard C++ Library helpful:

(if you don't want to install silverlight there is a button to download it in a normal video format towards the bottom right).
taz0010
taz0010
If your game needs to store a number of units that are routinely being killed off and respawned, and you need to maintain pointers/references to these objects, then std::list is your best bet. Pointers/references to objects in a list are only invalidated when the object itself is erased. And objects can be removed from and inserted into the list in O(1). Lists are only preferable in certain cases though. They lack random access, have a per-element space overhead and require dynamic allocation on every operation, which can be a serious bottleneck in a tight loop. Unless there are specific reasons not to, use vector as your general container of choice.
Noegddgeon
Noegddgeon
Thank you all very much for your posts and help. I will definitely be writing some code and experimenting with vectors and lists once I've finished this chapter on pointers and completed all of the exercise problems. I understand that, using vectors, you can create a virtually endless number of spawned beings with the push_back function. Of course, there are a million things I want to try out, and chances are high that I won't have a solid grasp on any of them until I actually sit down and code through all of them and learn from my mistakes. :] And I will definitely learn more about the Standard Library.... that's another couple of chapters in this book, as well as the subject of a couple of other books I have. Thanks again for all your guys' help.... hopefully soon I'll actually have some code samples and experiments to show and need some help for :p
21st Century Moose
21st Century Moose
Another alternative I like, and this is Windows only but I'm certain there are equivalents on other platforms, is to use VirtualAlloc to reserve a chunk of memory that's "big enough", commit memory from that chunk as required, and cast it as a (type **) of whichever type I'm interested in. You can nicely wrap this in a class that does all the heavy lifting for you, and the beauty is that if it needs to expand it can do so in the same consecutive memory region without having to move other references around. Remember I said "big enough" - how big is that? It depends on how many of each object type you want it to store. 1 MB can hold 256k pointers (assuming 32-bit) so I work around that.

I also keep a "scratch buffer" of about 1 MB handy for any time I need to quickly build a list of things and use it immediately. A very very useful thing to have.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
Zakwayda
Zakwayda
Quote:
Original post by mhagain
Another alternative I like, and this is Windows only but I'm certain there are equivalents on other platforms, is to use VirtualAlloc to reserve a chunk of memory that's "big enough", commit memory from that chunk as required, and cast it as a (type **) of whichever type I'm interested in. You can nicely wrap this in a class that does all the heavy lifting for you, and the beauty is that if it needs to expand it can do so in the same consecutive memory region without having to move other references around. Remember I said "big enough" - how big is that? It depends on how many of each object type you want it to store. 1 MB can hold 256k pointers (assuming 32-bit) so I work around that.

I also keep a "scratch buffer" of about 1 MB handy for any time I need to quickly build a list of things and use it immediately. A very very useful thing to have.
Don't forget vector::reserve() and resize(), boost::pool, and so on. (I just mention these because it sounds like you're doing some things manually and without type safety that could maybe be automated and/or made portable and type-safe. Not saying these solutions would be better necessarily, but just mentioning them as an option.)
Aardvajk
Aardvajk
Quote:
Original post by mhagain
Another alternative I like, and this is Windows only but I'm certain there are equivalents on other platforms, is to use VirtualAlloc to reserve a chunk of memory that's "big enough", commit memory from that chunk as required, and cast it as a (type **) of whichever type I'm interested in. You can nicely wrap this in a class that does all the heavy lifting for you, and the beauty is that if it needs to expand it can do so in the same consecutive memory region without having to move other references around. Remember I said "big enough" - how big is that? It depends on how many of each object type you want it to store. 1 MB can hold 256k pointers (assuming 32-bit) so I work around that.

I also keep a "scratch buffer" of about 1 MB handy for any time I need to quickly build a list of things and use it immediately. A very very useful thing to have.


In addition to jyk's comment, bear in mind that an implementation of the standard library written for a computer running Windows is likely using the API memory allocation functions (or whatever functions the API calls) to allocate and release memory.

You are probably reinventing a wheel that is less round than the one you already have. [smile]
21st Century Moose
21st Century Moose
Quote:
Original post by jyk
Quote:
Original post by mhagain
Another alternative I like, and this is Windows only but I'm certain there are equivalents on other platforms, is to use VirtualAlloc to reserve a chunk of memory that's "big enough", commit memory from that chunk as required, and cast it as a (type **) of whichever type I'm interested in. You can nicely wrap this in a class that does all the heavy lifting for you, and the beauty is that if it needs to expand it can do so in the same consecutive memory region without having to move other references around. Remember I said "big enough" - how big is that? It depends on how many of each object type you want it to store. 1 MB can hold 256k pointers (assuming 32-bit) so I work around that.

I also keep a "scratch buffer" of about 1 MB handy for any time I need to quickly build a list of things and use it immediately. A very very useful thing to have.
Don't forget vector::reserve() and resize(), boost::pool, and so on. (I just mention these because it sounds like you're doing some things manually and without type safety that could maybe be automated and/or made portable and type-safe. Not saying these solutions would be better necessarily, but just mentioning them as an option.)

All viable alternatives. :)

Sometimes the more hands-on stuff is needed if you're using plain C, other times you may want a degree of finer control, but that's up to your own needs, and if the stl or boost stuff is good enough for what you're doing, then it's good enough.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
cache_hit
cache_hit
Quote:
Original post by Aardvajk
Common approach would be to use a std::vector of pointers to your entities. You need to delete them when you are done though:

*** Source Snippet Removed ***

You might like to look into boost::ptr_vector instead.


I would definitely not recommend anything boost related given the OP's apparent experience with C++.
21st Century Moose
21st Century Moose
Quote:
Original post by AardvajkIn addition to jyk's comment, bear in mind that an implementation of the standard library written for a computer running Windows is likely using the API memory allocation functions (or whatever functions the API calls) to allocate and release memory.

You are probably reinventing a wheel that is less round than the one you already have. [smile]

Depends. The API HeapCreate/HeapAlloc/etc, for example, (which underlies malloc on Windows), lets you create and destroy multiple independent heaps on the fly and as you require. Need a chunk of unbounded memory for your particles, and need to be able to destory everything in that chunk at any arbitrary point and without affecting any other allocation? HeapCreate/HeapAlloc/HeapDestroy are your friends. If you need that kind of functionality then there's no harm in using them (and certainly less harm than in wrapping malloc or another allocator with the same kind of functionality). Also very handy if you're using C and don't have access to STL.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.