Say I have a C++ class called MainComponent and it has a few classes inside of it: WindowClass, InputClass, GameClass. The main function is setup like so:
int main()
{
MainComponent app;
app.start(); // Initializes the MainComponent class, opens window, starts game and all that.
return 0;
}
The MainComponent class is expected to possibly get very big because of included objects of GameClass and such. Should MainComponent app be dynamically allocated with new? or should I allocate the GameClass objects with new inside the MainComponent class? or is it just fine to leave it on the stack as long as it runs fine or what?
Depends on what 'big' means. This link shows the default stack size limits for some OSes. You'll want to make sure that the size MainComponent allocates on the stack is well below any of these numbers.
Further, if there are certain things being dynamically created, or certain arrays/assets that are too large, which fall under MainComponent or another struct that is below MainComponent, then you can always heap-allocate that struct/array/class while still keeping MainComponent itself on the stack.
Conceptually, keeping MainComponent on the stack makes more sense as its lifecycle is being modeled exactly by its scope in the main function.
To answer your more general question, How to decide what goes on the stack?, consider three aspects:
Ownership. Is the ownership of a particular data structure clear? Does it explicitly belong to a particular function (and its descendants), or a particular struct/class and can be modeled with RAII?
Lifecycle. Is the particular data structure expected to exist within a timeline that closely resembles a lifetime of the class that created it, or the function that created it? What is the scope?
Is the size known at compile-time? This comes up when allocating arrays of a variable size. This is the case with many STL containers. In that case, the basic struct/class includes a few things on the stack and then maintains pointers to heap-allocated structures.
You said:
MainComponent class is expected to possibly get very big because of
included objects of GameClass
object size is constant. for example: empty std::string has the same sizeof as very long std::string, it is the same for any object.
the sizeof(object) is the only bytes it take on the stack. all the rest anyway goes to the heap.
so if you reach to stack limits and got stack overflow exceptions, then you should try to move some objects to heap. or if it is a single object (like your MainComponent class appear to be), you can also use the singleton pattern, or just declare it as static, to remove it from the stack to other segments of memory.
Related
I am (re-) learning C++ (again, after many years of Java and Python), but it seems I am not familiar with the concepts of heap and stack any more. I am reading threads like this one, which makes it quite clear: local variables in functions/methods live on the stack and will be destroyed when leaving that function/method. For objects that I need longer I would need to allocate memory on the heap.
Fine. But not I am reading a bit of C++ code and see the following (simplified):
struct MyStruct
{
int Integer;
bool Boolean;
}
// in header file
class MyClass
{
TArray<MyStruct> MyArray; // TArray is a custom dynamic array in the framework
void FillArray();
TArray<MyStruct> GetArray() { return MyArray; }
}
// in cpp file
void MyClass::FillArray()
{
for(int i = 0; i < 10; ++i)
{
MyStruct s; // These objects are created on the stack, right?
s.Integer = i;
s.Boolean = true;
MyArray.Add(s);
}
}
So there is a custom struct MyStruct, and a class that has a container MyArray. Then at some point I call MyClass->FillArray() to initialize the array. In that method I create objects of MyStruct on the stack (i.e. not via new) and add them to the array. From my understanding these objects within the array should be destroyed as soon as the FillArray() methods returns.
Now at some point later in code I call MyClass->GetArray(). And to my surprise the array returned does indeed contain all the struct objects that have been created before.
Why are these struct objects still there, why have they not been destroyed as soon as the FillArray() method returns?
Matthias, you seem to have grasped the concept of "stack" and "heap" variables correctly enough. The "magic" you missed is that MyArray::Add clones the provided s and thus its value lives on in the MyArray instance.
If you find "stack-" variables mysterious just think of them as any scoped variable. A scoped variable is destructed when it goes out of scope. And a local variable of a function is just a special case of a scope.
To have data "live on" outside a scope you need to create it on the heap (use new) and pass on the pointer to its location by value. This is also true if you want to share data between threads. Another thread-of-execution is just execution using a call-stack of its own. And thus two threads calling the same function will have their separate local (stack) variables. So understanding the stack-concept is good when you wander into the land of multi-threading.
In garbage collected languages, on the other hand, all data is treated as if "on the heap" and accessed thorough reference counted "pointers". Thus in e.g., C# and Java you don not normally talk about "stack-" versus "heap-" variables.
Many C++ classes implements some "magic" internally to optimise its internal storage for you. C++ strings for example may implement short string optimisation in that stores "short strings" locally (on the stack) and longer strings on the heap (using new). It then applies the RAII idiom to clean up any heap-memory on destruction. In this way you as client does normally not have to care. Just as in your example where you do not have to care how TArray handles its internal memory. You just make sure you pass the values to it correctly.
Good luck with learning C++ again :)
MyArray.Add takes a struct that's in the stack.
The question is wether it takes it by reference or by value.
If it takes it by reference (pointer), then once it goes out of scope you'll end up in a mess.
If it takes it by value, it copies the values (creating duplicates in a different scope).
It seems like what MyArray.Add does is create a new struct with the same values as it's parameter.
I'm developing a game server for a video game called Tibia.
Basically, there can be up to millions of objects, of which there can be up to thousands of deletes and re-creations as players interact with the game world.
The thing is, the original creators used a Slot Map / Object Pool on which pointers are re-used when an object is removed. This is a huge performance boost since there's no need to do much memory reallocation unless needed.
And of course, I'm trying to accomplish that myself, but I've come into one huge problem with my Slot Map:
Here's just a few explanation of how Slot Map works according to a source I found online:
Object class is the base class for every game object, my Slot Map / object Pool is using this Object class to save every allocated object.
Example:
struct TObjectBlock
{
Object Object[36768];
};
The way the slot map works is that, the server first allocates, say, 36768 objects in a list of TObjectBlock and gives them a unique ID ObjectID for each Object which can be re-used in a free object list when the server needs to create a new object.
Example:
Object 1 (ID: 555) is deleted, it's ID 555 is put in a free object ID
list, an Item creation is requested, ID 555 is reused since it's on
the free object list, and there is no need to reallocate another
TObjectBlock in the array for further objects.
My problem: How can I use "Player" "Creature" "Item" "Tile" to support this Slot Map? I don't seem to come up with a solution into this logic problem.
I am using a virtual class to manage all objects:
struct Object
{
uint32_t ObjectID;
int32_t posx;
int32_t posy;
int32_t posz;
};
Then, I'd create the objects themselves:
struct Creature : Object
{
char Name[31];
};
struct Player : Creature
{
};
struct Item : Object
{
uint16_t Attack;
};
struct Tile : Object
{
};
But now if I was to make use of the slot map, I'd have to do something like this:
Object allocatedObject;
allocatedObject.ObjectID = CreateObject(); // Get a free object ID to use
if (allocatedObject.ObjectID != INVALIDOBJECT.ObjectID)
{
Creature* monster = new Creature();
// This doesn't make much sense, since I'd have this creature pointer floating around!
monster.ObjectID = allocatedObject.ObjectID;
}
It pretty much doesn't make much sense to set a whole new object pointer the already allocated object unique ID.
What are my options with this logic?
I believe you have a lot of tangled concepts here, and you need to detangle them to make this work.
First, you are actually defeating the primary purpose of this model. What you showed smells badly of cargo cult programming. You should not be newing objects, at least without overloading, if you are serious about this. You should allocate a single large block of memory for a given object type and draw from that on "allocation" - be it from an overloaded new or creation via a memory manager class. That means you need separate blocks of memory for each object type, not a single "objects" block.
The whole idea is that if you want to avoid allocation-deallocation of actual memory, you need to reuse the memory. To construct an object, you need enough memory to fit it, and your types are not the same length. Only Tile in your example is the same size as Object, so only that could share the same memory (but it shouldn't). None of the other types can be placed in the objects memory because they are longer. You need separate pools for each type.
Second, there should be no bearing of the object ID on how things are stored. There cannot be, once you take the first point into consideration, if the IDs are shared and the memory is not. But it must be pointed out explicitly - the position in a memory block is largely arbitrary and the IDs are not.
Why? Let's say you take object 40, "delete" it, then create a new object 40. Now let's say some buggy part of the program referenced the original ID 40. It goes looking for the original 40, which should error, but instead finds the new 40. You just created an entirely untrackable error. While this can happen with pointers, it is far more likely to happen with IDs, because few systems impose checks on ID usage. A main reason for indirecting access with IDs is to make access safer by making it easy to catch bad usage, so by making IDs reusable, you make them just as unsafe as storing pointers.
The actual model for handling this should look like how the operating system does similar operations (see below the divide for more on that...). That is to say, follow a model like this:
Create some sort of array (like a vector) of the type you want to store - the actual type, not pointers to it. Not Object, which is a generic base, but something like Player.
Size that to the size you expect to need.
Create a stack of size_t (for indexes) and push into it every index in the array. If you created 10 objects, you push 0 1 2 3 4 5 6 7 8 9.
Every time you need an object, pop an index from the stack and use the memory in that cell of the array.
If you run out of indexes, increase the size of the vector and push the newly created indexes.
When you use objects, indirect via the index that was popped.
Essentially, you need a class to manage the memory.
An alternative model would be to directly push pointers into a stack with matching pointer type. There are benefits to that, but it is also harder to debug. The primary benefit to that system is that it can easily be integrated into existing systems; however, most compilers do similar already...
That said, I suggest against this. It seems like a good idea on paper, and on very limited systems it is, but modern operating systems are not "limited systems" by that definition. Virtual memory already resolves the biggest reason to do this, memory fragmentation (which you did not mention). Many compiler allocators will attempt to more or less do what you are trying to do here in the standard library containers by drawing from memory pools, and those are far more manageable to use.
I once implemented a system just like this, but for many good reasons have ditched it in favor of a collection of unordered maps of pointers. I have plans to replace allocators if I discover performance or memory problems associated with this model. This lets me offset the concern of managing memory until testing/optimization, and doesn't require quirky system design at every level to handle abstraction.
When I say "quirky", believe me when I say that there are many more annoyances with the indirection-pool-stack design than I have listed.
I am new to C++ but I have some basic memory allocation knowledge in C. I am writing a class Card, which stores the card number and a list of class Activity object.
class Card {
public:
Card();
~Card();
vector<Activity> activities;
int cardNo;
}
Currently, I initialize the Activity object using code like:
Activity a = Activity("a");
and push them to the vector defined in the Card object.
But I found people tend to initialize using Activity *a = new Activity("a") instead (dynamically allocation?), and the objects declared in the former way (statically allocated?) will be freed when the function declares them terminated.
Then, if I initialize Activity objects the same way I did before, but initialize Card using the "new Card()" way, is it possible that the Activity objects may have been de-allocated before Card object freed? Should I switch to use "new Activity()" to initialize objects stored in Card?
No, what you're doing is fine. When you push an object onto a vector, a copy is made. So when your function returns, your a is destroyed, but the vector you added it to still has its own seperate copy.
One reason someone might allocate an instance of a class dynamically and push it onto a vector would be that copying objects of that particular class around is expensive (and vector does a lot of copying around internally) and they want to avoid that, so they store pointers instead of objects so that only copies of the pointers are made, not of the objects (which is would not be nearly so expensive). That all depends on the class though; generally you can use vectors of objects without any performance issues.
Note: a shortcut1 for Activity a = Activity("a"); is Activity a("a"), or better, do what Benjamin suggested and do activites.push_back(Activity("a")) if you're not performing some operations on the Activity before you push it.
1 It's not really a shortcut because it does something different, but for your intents and purposes, it is.
"But I found people tend to initialize using Activity *a = new
Activity("a") instead (dynamically allocation?)"
What people? They're doing it wrong. You're doing it right, sort of. You could just do this instead:
activities.push_back(Activity("a"));
A few cases where you need pointers:
it might be NULL instead of some dummy state
it is polymorphic
shared, not exclusive to the class
there is a circular dependency or recursion that prevents a direct member variable
In this particular case, as with most STL containers, member variables are preferred over member pointers.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
When to use “new” and when not to, in C++?
When should I use the new keyword in C++?
It seems like I could program something without ever using the word new, and I would never have to worry about deleting anything either, so why should I ever call it?
From what I understand, it's because I would run out of stack memory.
Is this correct? I guess my main question is, when should I call new?
It's a matter of object lifetime: if you stack-allocate your objects, the objects destructors will be called when these objects go out of scope (say, at the end of the method). This means that if you pass these objects out of the method that created them, you'll find yourself with pointers to memory that could be overwritten at any time.
It's because you may not know at compile time whether you need an object, or how many, or of what type. The new operator allows you to dynamically allocate objects without having to know such things in advance.
Here's an example of not knowing the type of object in advance:
class Account { ... };
class CheckingAccount : public Account { ... };
class VisaAccount : public Account { ... };
...
Account *acct = type == "checking" ? new CheckingAccount : new VisaAccount;
The main reason you'll need to use new/delete is to get manual control the lifetime of your objects.
Other reasons are already provided by others but I think it's the more important. Using the stack, you know exatly the lifetime of your objects. But if you want an object to be destroyed only after an event occurs, then it cannot be automatically defined.
The lifetime of the data/objects created on the stack is restricted to the block. You cannot return references/pointers to it. For data to be available across functions, you can create it on the heap with new. Of course, it can be at a higher level, or even global. But you seldom know at compile time how much data/how many objects will be needed at run time.
You can write a many non-trivial programs without ever calling "new." (or thus delete).
What you wouldn't be able to do (at least without writing or using your own equivalents) is decide what type of objects or how many you want to create at run-time, so you'd be limiting yourslef.
[updated]
You can use new to create new instance of some class, or allocate memory (for array for example), like
Object o = new Object();
Before creating new instance of class Object, you cannot use it. (Unless you have static methods.)(this is just one example of usage, sometimes other objects will instantiate or destroy objects that you need/don't need)
There are many good answers here but it is difficult to explain everything about new in one reply on SO, and if you do not understand what happens when new is called then it is difficult to know when to use it. This is one of the most important areas in programming so, after reading basic information here you should study it in more detail. Here is one of possible articles where you could start your research:
http://en.wikipedia.org/wiki/New_%28C%2B%2B%29
Topics that you will have to learn in order to understand what happens when you call new, so that you then could understand when to call it (there are more probably but this is what i can think of now):
- constructors (and destructors)
- static classes and methods
...
So the question is relatively straight forward, I have several semi-large lookup tables ~500kb a piece. Now these exact same tables are used by several class instantiations (maybe lots), with this in mind I don't want to store the same tables in each class. So I can either dump the entire tables onto the stack as 'static' members, or I can have 'static' pointers to these tables. In either case the constructor for the class will check whether they are initialized and do so if not. However, my question is, if I choose the static pointers to the tables (so as not to abuse the stack space) what is a good method for appropriately cleaning these up.
Also note that I have considered using boost::share_ptr, but opted not to, this is a very small project and I am not looking to add any dependencies.
Thanks
Static members will never be allocated on the stack. When you declare them (which of course, you do explicitly), they're assigned space somewhere (a data segment?).
If it makes sense that the lookup tables are members of the class, then make them static members!
When a class is instanced on the stack, the static member variables don't form part of the stack cost.
If, for instance, you want:
class MyClass {
...
static int LookUpTable[LARGENUM];
};
int MyClass:LookUpTable[LARGENUM];
When you instance MyClass on the stack, MyClass:LookUpTable points to the object that you've explicitly allocated on the last line of the codesample above. Best of all, there's no need to deallocate it, since it's essentially a global variable; it can't leak, since it's not on the heap.
If you don't free the memory for the tables at all, then when your program exits the OS will automatically throw away all memory allocated by your application. This is an appropriate strategy for handling memory that is allocated only once by your application.
Leaving the memory alone can actually improve performance too, because you won't waste time on shutdown trying to explicitly free everything and therefore possibly force a page in for all the memory you allocated. Just let the OS do it when you exit.
If these are lookup tables, the easiest solution is just to use std::vector:
class SomeClass {
/* ... */
static std::vector<element_type> static_data;
};
To initialize, you can do:
static_data.resize(numberOfElements);
// now initialize the contents
With this you can still do array-like access, as in:
SomeClass::static_data[42].foo();
And with any decent compiler, this should be as fast as a pointer to a native array.
Why don't you create a singleton class that manages the lookup tables? As it seems they need to be accessed by a number of classes; make the singleton the manager of the lookup tables accessible at global scope. Then all the classes can use the singleton getters/setters to manipulate the lookup tables. There are 3 advantages to this approach:-
If the static container size for the
lookup tables becomes large then the
default stack-size may ( 1MB on
Windows) lead to stack-overflow on
application statrt-up itself. Use a container that allocates dynamically.
If you plan to access the table via multiple-threads, the singleton class can be extended to accompany locked access.
You can also cleanup in the dtor of singleton during application exit.
I can think of several ways to approach for this depending upon what is trying to be accomplished.
If the data is static and fixed, using a static array which is global and initialized within the code would be a good approach. Everything is contained in the code and loaded when the program is started so it is available. Then all of the class which need access can access the information.
If the data is not static and needs to read in, an static STL structure, such as a vector, list or map would be good as it can grow as you add elements to the list. Some of these class provides lookup methods as well. Depending upon the data you are looking up, you may have to provide a structure and some operator to have the STL structures work correctly.
In either of the two case, you might what to make a static global class to read and contain the data. It can take care of managing initialization and access the data. You can use private members to indicate if the class has been read in and is available for use. If it has not, the class might be able to do the initialization by itself if it has enough information. The other class can call static function of the static global class to access the data. This provides encapsulation of the data, and then it can be used by several different classes without those classes needing to incorperate the large lookup table.
There are several possibilties with various advantages and disadvantages. I don't know what the table contains, so I'll call it an Entry.
If you just want the memory to be sure to go away when the program exits, use a global auto_ptr:
auto_ptr<Entry> pTable;
You can initialize it whenever you like, and it will automatically be deleted when the program exits. Unfortunately, it will pollute the global namespace.
It sounds like you are using the same table within multiple instances of the same class. In this case, it is usual to make it a static pointer of that class:
class MyClass {
...
protected:
static auto_ptr<Entry> pTable;
};
If you want it to be accessible in instances of different classes, then you might make it a static member of a function, these will also be deleted when the program exits, but the really nice thing is that it won't be initialized until the function is entered. I.e., the resource won't need to be allocated if the function is never called upon:
Entry* getTable() {
static auto_ptr<Entry> pTable = new Entry[ gNumEntries ];
return pTable;
}
You can do any of these with std::vector<Entry> rather than auto_ptr<Entry>, if you prefer, but the main advantage of that is that it can more easily be dynamically resized. That might not be something you value.