Allocate my main game object on the stack, on the heap, or in the data segment (C++)

Started by
9 comments, last by Ravyne 14 years, 11 months ago
All of my game subsystems are contained inside a GAME object that's the highest level object in my game's class hierarchy. The GAME class exposes a public "Start" function, which kicks off the main game loop and doesn't return until the user quits the game or an unrecoverable errors occurs. I'm not sure where the main GAME object should be placed in memory. I ask because I think it's potentially pretty large, and I don't have any requirements that would force it into one area. Put another way, I don't know what my main.cpp should look like; I can think of 3 options: stack:

void main()
{
GAME game;
game.Start();
}
heap:

void main()
{
GAME * game = new GAME();
game->Start();
delete game;
}
data segment:

GAME game;
void main()
{
game.Start();
}
My question is, is there one of the above three that's better than the rest, or another alternative that's better? Or does it not matter at all? I'm using GCC and will be developing on windows, linux, and osx.
Advertisement
By default you should put variables on the stack.
Put things on the stack when you don't have a reason not to.

Classes like std::vector will automatically manage things on the heap for you, while the instance itself lives on the stack. This is quite convenient.

By the way, you want int main() in C++.
GAME can't be "potentially" large - either it's large, or it's not. If it's large, put it on the heap. If it's not, put it on the stack.
Quote:Original post by nullsquared
GAME can't be "potentially" large - either it's large, or it's not. If it's large, put it on the heap. If it's not, put it on the stack.


Its true that its size is a known quantity, but there's no good reason to put it on the heap.


My system works the same exact way. My main function consists of creating a mutex object (if this fails, I know an instance of my app is already running and I shut down), Creating/Initializing my application object, and kicking off my main loop by calling a method on my application object. It returns an int, which is the code to be returned by main.


For all intents and purposes this is a style thing --

Since, under this scenario, it is unlikely that a global instance of Game would be exported to any other code (in fact, its highly unlikely that there would even be a "main.h" file, let alone that you would extern the global instance), and all work essentially takes place under Game, the usual worries of global mutable state are minimized if not non-existent. The only real drawback to a global in this instance is that you give up precise control of when the Game instance is created or destroyed. All you know is that it is created "some time" before main() is entered, and destroyed "some time" after main is exited -- in most circumstances, you don't need to know any more than this. I believe the object will exist in the data segment under this scenario.

Next up is creating it on the stack -- here, the semantics (that is, reference rather than pointer) stay the same, without having the object in the global name space at all. The only real difference is that you now know that the object is created "as" the main function is entered, and it is destroyed "as" the function is exited. Pretty much the same, for all practical purposes, as a non-exported global instance. The object will exist on the stack in this scenario.

As a short aside, you could create a static local instance of game, which would IIRC, allocate storage in the data segment. Under this scenario, the name of the instance would not be available to the global namespace, and the object would be constructed on the initial call to main(), and destroyed some time after main is exited, similar to a global.

Lastly, you can create a new object on the heap by new'ing one up. You'll end up with pointer semantics, so you'll have to dereference before calling member functions, though you only call the main loop function (and possibly some init/shutdown member functions), so its not like the extra characters will kill you. The one, potentially big, thing you gain is exact control over the time of the object's construction/destruction -- this could be useful I suppose, but I have a hard time thinking of any scenarios which wouldn't be better served by appropriate use of other means.


I really don't think there's any strong argument for one approach over any of the others. Personally, my objects are created on the stack because it has easier semantics than creating on the heap via new, and I don't have a need to precisely control the time of construction/destruction. I prefer stack instances over global instances simply because going global gains nothing (and as I explained, doesn't really loose anything practical either) -- this really goes back the the general rule of thumb that instances should be created on the stack unless there's a good reason to make them global instead.

throw table_exception("(? ???)? ? ???");

Thanks for the advice! I am currently allocating my GAME object on the stack simply because I think it looks nicer, but wanted to make sure I wasn't overlooking some other aspect. I will continue to allocate it on the stack.
How large is large?

Generally automatic allocation is fine but occasionally you can blow the stack if you go overboard with recursion or local arrays. What the limits and consequences of exceeding them are depends on the system, for instance Win32 reserves a full megabyte of virtual memory per thread by default and overflows can be handled gracefully though structured exception handling.
Then again there are few things as frustrating as trying to proof embedded applications, where the stack is often tiny and lacking memory protection, from potential overruns.
Stack limits are a good point, particularly on anything that's not a PC or Console from the last couple generations.

I guess I was relying on my own experience to infer that, at least in my case, the application class is relatively small -- It composes a couple other classes directly (nothing too sizable), and those classes are themselves composed of a few bytes of data, the rest being dynamically allocated -- but I suppose I can't presume to know that about the OP's code. It does stand to reason that if the OP has gone through the trouble of structuring his code in this way, though, that the chain of composited classes isn't too heavy to carry on the stack.

To the OP, if your game class (itself or indirectly) actually is large -- say more than a 1k, then you may want to either re-structure to reduce the static size of that class, or instance it by some other means.

throw table_exception("(? ???)? ? ???");

Quote:Original post by RavyneTo the OP, if your game class (itself or indirectly) actually is large -- say more than a 1k, then you may want to either re-structure to reduce the static size of that class, or instance it by some other means.


Let's see... sizeof(GAME) is 10516. The platforms I'm on are Windows, Linux, and OSX. No consoles or embedded anything.
Quote:Original post by venzon
Quote:Original post by RavyneTo the OP, if your game class (itself or indirectly) actually is large -- say more than a 1k, then you may want to either re-structure to reduce the static size of that class, or instance it by some other means.


Let's see... sizeof(GAME) is 10516. The platforms I'm on are Windows, Linux, and OSX. No consoles or embedded anything.


Do you have lots of arrays in the class or its members or something?

This topic is closed to new replies.

Advertisement