Skip to main content
GameDev.net gamedev.net
🔒 Locked

Stack/Heap allocation for class fields

Started by Alpha Nox Jun 27, 2011 at 3:10 AM 1 replies 2.3k views
Original Post
Alpha Nox
Alpha Nox
Hello all,

I'm having some difficult with C++ when it comes to decide whether or not to use heap or stack allocation. So far, I believe I have understood the basics, please correct me if I'm wrong.

- Stack allocation: faster, automatically freed and should be used for 'small types' since it's usually a lot smaller than heap (though, the size is definable on the compiler)
- Heap allocation: slower and you have to manage it (manual release)

Therefore, from I what understand, inside a function, if the object to be created is 'small' then it should be put on the stack, otherwise one should put it in the heap.


My main doubt right now is what happens when they're fields (attributes) of a class. For example, please consider the following simplified class hierarchy:


class Timer {
std::string name;
int duration;
int elapsedTime;
public:
// ( . . . )
};



class Frame {
std::string sourceImageId;
int sourceX,
sourceY,
sourceW,
sourceH;
int duration;
public:
// ( . . . )
};



class Animation {
Timer timer;
std::vector<Frame> frames;
int currentFrame;
public:
// ( . . . )
};


class CharacterStackAnim {
Animation animation;
public:
// ( . . . )
};



// Same class as above except that it allocates Animation dynamically
class CharacterHeapAnim {
Animation* animation;
public:
CharacterHeapAnim() { animation = new Animation(); }
~CharacterHeapAnim() { delete animation; }
// ( . . . )
};


1. If I allocate a CharacterStackAnim in the heap (using operator new), does the 'animation' field also get stored in the heap? Is there any difference from allocating CharacterHeapAnim on the heap?

2. How does one decide whether to make a field (like animation) a pointer or not (whether or not to dynamically allocate it)? Consider that the animation won't be shared with other characters.

3. In Animation, what would be better std::vector or std::vector? What do you need to consider in order to answer such a question?


I would be very grateful if you could answer these questions or point me to a good source for further studies.


Thanks in advance,
Victor Freire
ApochPiQ
ApochPiQ
You can think of it like this: an object (instance of a class) is sort of like a set of Russian nesting dolls. The biggest "doll" contains the outermost data of the object; each doll inside it consists of the data associated with each member of the class. Where this memory goes depends on where the biggest doll is allocated: if you allocate the big doll on the stack, the internals will (generally speaking) go on the stack, unless they internally allocate other memory on the free-store (technically it may or may not be a heap). If you allocate the doll on the free-store, then all of its internals go there instead.

This can get messy for classes like the standard library containers, strings, etc.; you can allocate, for instance, a string on the stack, but past a certain size, the class will generally start allocating memory for the string data from the free-store. So it's entirely possible to mix the two models. Note, however, that once something lives on the free-store, its members will always also live on the free-store; while you can allocate an object on the stack which stores additional data on the free-store, the inverse is not possible without some genuine evil hackery.

So: the answer to your first question is that the animation field would indeed be on the free-store. The difference between your "stack" and "heap" classes is that the "heap" version can never allocate the Animation data on the stack; it'll always be on the free-store. Another important difference is that your "heap" version introduces an extra layer of indirection between the Character and the Animation. This can lead to problems like cache misses, memory fragmentation, and so on if taken to extremes. Generally it is wisest to keep your members allocated directly instead of as pointers to elsewhere on the free-store, so you can avoid indirection overhead. The exception, of course, is if you want dynamically resizable storage (as comes with SC++L containers, for instance) for objects which are initially stack-allocated.

For your second question: prefer direct membership in most cases. The two main exceptions are if you need dynamically resizable storage for some reason (and therefore you can't just allocate it all up front for stack-allocated objects) or if you need shared access to a single resource from multiple locations. (Even then, it's generally best to use references instead of pointers anywhere possible, and almost always better to use a smart pointer class instead of a raw pointer.)

This applies partially to your third question as well: you should prefer storing objects by value instead of by pointer inside containers. The exception is again if you need to point to a shared resource of some kind, say, if you need a list of textures where many objects might share those same texture objects. In this case, though, it is again advisable to use smart pointers instead of raw pointers.

There is one final consideration to keep in mind, which is the allocation behaviour of std::vector. If you store a vector of objects, and then add another object onto the end of the vector, you will probably have to incur the expense of deleting all the existing objects, copying their data into a new location, and then adding the new value onto the end of the container. This can get expensive very quickly, so it might pay to use a class like std::list instead if you need to insert and remove items a lot. Otherwise, if possible, use std::vector::reserve() to pre-allocate memory so that you can insert up to a required number of objects before having to do the copy/reallocate dance.


I highly recommend the C++ FAQ site for more insight into these issues, as well as many other areas not touched on by the immediate subject at hand.


Best of luck!
Alpha Nox
Alpha Nox

( . . . )


That was very informative. I thought that if you did not allocate a class field with new it would always be placed on the stack just like a local variable. Expanding upon your intuitive Russian doll analogy, it could be said that when you use a pointer instead of the class directly, the outer doll contains a 'note' with the position of the inner doll instead of the actual doll.

Coincidentally, I was reading the C++ faq lite but I didn't find any section nearly as informative for this topic.

All in all, thanks a lot! I'll be reviewing my design now. =)

Victor Freire

Topic Locked

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

Sign in to reply to this topic.