Help with memory allocation for multiplayer game server - c++

I'm kind of new to C++ development in linux and I'm trying to make a multiplayer game. I know that it is a bit of complex program to start but I have some background on this type of program from other languages so I guess the most difficult part is taming the language.
Although I'm programming a multiplayer game, my doubts are about the best way to handle the memory and avoid leaks in C++.
My doubts are about allocating memory for the client objects and for the game tables. For the client objects I've read that the std containers handle the memory allocation for me. I don't know if this memory is allocated on heap so I've decided to use a map of pointers (with the socket fd as key) to client object. This way, I have something like this when a client connect and disconnect:
Daemon.cpp
map<int,Client*> clientList;
//Do server stuff
//Add connected client to list
void onConnect(int socketFd) {
clientList[socketFd] = new Client();
}
//remove connected client from list
void onDisconnect(int socketFd) {
delete clientList[socketFd];
clientList.erase(socketFd);
}
The Client class is a simple class that has a virtual destructor, some client parameters (like IP, connected time, etc) and some methods (like send, etc). Is this the best way to keep track of clients without memory problems? I guess I still have to add exceptions handling on new Client() allocations...
The second part, and I guess the most difficult for me, is about the game tables. Clients can enter and leave tables of games. I have a table class with a lot of parameters, constants and methods. I'm creating all the game tables on start up on the same Daemon.cpp described above:
Daemon.cpp
GameTable *tables;
int main() {
tables = new Chess[MAX_NUMBER_OF_TABLES];
}
Some explanations: GameTable is the base class for all games. It is an interface with base parameters and virtual game functions (like doCommand, addClient, removeClient, etc). Chess class is the implementation of the chess game, it inheritance (sorry bad english) from GameTable. Questions:
1) Is this the best way (memory) to handle it?
2) Chess class has a lot of parameters, when I allocate the table list of Chess objects do the memory for all objects already allocated or I have to allocate and dealocate inside Chess class (with constructors and destructors)?
My third question is how to add and remove clients to/from tables. First I thought in creating a simple vector with clients like:
GameTable.h
vector <Client> clientInTable;
Chess.cpp
//Add client to table
void addClient(Client &client) {
clientInList.push_back(client);
}
//remove client from table
void removeClient(Client &client) {
//search client on list, when found get position pos
clientList.erase(pos);
}
Soon I've noticed that when I remove the client its destructor was called. It must not happen! Than I thought in use a vector of pointers like:
GameTable.h
vector <Client*> clientInTable;
Chess.cpp
//Add client to table
void addClient(Client *client) {
clientInList.push_back(client);
}
//remove client from table
void removeClient(Client *client) {
//search client on list, when found get position pos
clientList[pos] = NULL;
}
Is this the best way to handle it? Thanks everybody for the help.

Everything that is dynamically allocated should have something that 'owns' the responsibility for deleting it - typically this should be an auto allocated struct/classs that uses RAII.
Use smart pointers such as std::auto_ptr and std::tr1::shared_ptr to store dynamically allocated objects, and use memory managing containers such as boost::ptr_vector and boost::ptr_map for storing multiple dynamically allocated objects in a single container.
Doing this kind of thing manually is error prone, difficult and, seeing as good solutions already exist, pointless.
This:
GameTable *tables;
int main() {
tables = new Chess[MAX_NUMBER_OF_TABLES];
}
Is extremely dangerous. An array of Chess cannot be used interchangeably with an array of GameTable. The compiler lets it pass because a pointer to Chess can be used as a pointer to a GameTable.
Arrays are contiguously packed - if size_of(Chess) is different to size_of(GameTable), indexing into the array will result in indexing into the middle of an object possibly followed by an access violation (that's the most likely scenario, you're actually invoking undefined behaviour).

Using smart pointers is a good way to avoid memory leaks
Consider boost ones:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm

A good strategy would be to set statically the maximum number of clients that can be managed by your server.
Then you build all Client objects required to manage all the clients from start (in an array or vector).
You will then re-use Client objects when there is a new connection, end using one when the client disconnects.
That require that your Client object is made in a way that allow reuse : the initialization and "termination" of it's use have to be explicit functions (init() and end() for example, something similar).
When you can, allow from start all resources you will ever need and reuse the objects. That way you limit memory fragmentation and get faster to the "worst case".

Inside onDisconnect, I would recommend calling clientList[socketFd] = NULL; after the connection is destroyed. This would make sure you aren't keeping an already-freed pointer around which can open up the door for problems later. This may already be handled by your clientList.erase method, but I thought I'd mention it just in case.
There might be a problem with the way you declared your Chess array. The pointer tables is defined as a pointer-to-GameTable, but it is pointing to an array of Chess objects. If a Chess object is nothing more than a GameTable object with a different name, then this code should work. However, if the definition of Chess adds anything to itself after it inherits from GameTable then you will change the size of the object and you will not be able to iterate through the array with that pointer. For example, if sizeof(GameTable) is 16 bytes and sizeof(Chess) is 24 bytes (perhaps due to some added member data), then tables[1] will refer to a memory location in the middle of the first Chess object in the array, not the beginning of the second item in the array as intended. Polymorphism lets you treat a derived class as if it were an object of its parent's class for the sake of using inherited members, but it's not safe to cast a pointer to a derived type into a pointer to the parent type for the sake of accessing an array.
Regarding adding clients to tables, can a client be associated with more than one table at a time? If not, give each table a unique ID of some sort and give each client a field called (for instance) current_table. When the client joins a table, store that table's ID in the field. When the client leaves the table, zero out the value. If a client can join multiple tables, this field can be turned into an array (current_tables[MAX_TABLES_PER_CLIENT]) and treated similarly.
Alternatively, you can create something like:
struct mapping {
clientId_t client_id;
tableId_t table_id;
};
struct mapping client_table_map[MAX_NUM_CLIENT_TABLE_MAPS] = {0};
When a client joins a table, create a new mapping structure containing the unique IDs of the client and table and add it to the list. Delete the entry when the client disconnects from the table. Now, you will have a table of all current connections that you can cross-reference in either direction (find all clients using a table or find all tables in use by a client).

Related

Using raw pointers without allocating memory

I would like to ask about my approach to using pointers raw pointers without allocating any memory using pointers. I am working on an application, that is simulating classical cashdesk. So I have a class CashDesk, which is containing vectors of Items and vector of Orders, which are classes to represent items and orders. Furthermore, I want the Order class to contain a vector, which would be a vector of pointers to Item – I don't want to store the object multiple times in different orders, because it makes no sense to me. Through the pointers in Order, I only want to be able to access properties of the class Item, there is no allocating of memory using the pointers.
Simplified code:
class CashDesk {
vector<Item> items;
vector<Order> orders;
}
class Order {
vector<Item*> ItemsInOrder;
}
Class Item containing only structured data – information about the Item.
I create all objects at the level of the CashDesk class – create instance of Item when needed and push it to items vector.
I have been told that I should avoid using raw pointers unless there is no another option. The important thing is that I don't use any memory allocation using pointers – really using the pointer in terms of pointing at the object and accessing it's properties. Should I rather use something like unique_ptr, or completely different approach?
Thanks for any response.
I have been told that I should avoid using raw pointers unless there is no another option.
You have been told something subtly wrong. You should avoid owning raw pointers, but non-owning raw pointers are perfectly fine.
You will have to ensure that the elements of Order::itemsInOrder aren't invalidated by operations on CashDesk::items, but that co-ordination should be within the private parts of CashDesk.
You could be more explicit about the lack of ownership semantic, by using std::vector<Item>::iterator in place of Item *, but that doesn't change any behaviour (a conforming implementation may implement std::vector<Item>::iterator as an alias of Item *)

c++ dynamic array of pointers - when i need to use it?

I'm trying to understand when I need to allocate an array of an object that each pointer to some object for example array of Student that point to Student:
Student** db = new Student*[size]
when do I need to use it? I know that is a general question, but I'm trying to solve some Exam that combines inheritance, and in some class, one of the data member they declare it as I said above.
in my solution i wrote:
Student * db = new Student[size];
thanks.
TL;DR version:
Use std::vector<std::unique_ptr<Student>> db.
Explanation
Student** db = new Student*[size]
could be used to represent an array of classes derived from Student.
eg:
Student** db = new Student*[size];
db[0] = new Grad_Student();
db[1] = new Coop_Student();
db[2] = new Elementary_Student();
If you elect the second option
Student * db = new Student[size];
db[0] = Grad_Student();
db[1] = Coop_Student();
db[2] = Elementary_Student();
you save a lot of pesky manual memory management by directly holding Students rather than pointers to Students, but Object Slicing will turn the derived Students into plain old Students. A box sized and shaped to fit a Student can only store a Student, so all of the additional features of, for example, the Grad_Student assigned to db[0] will be lost. Only by storing a reference to the Grad_Student can the Grad_Student's extensions be preserved. You just have to remember that the Grad_Student is actually stored somewhere else.
Sounds good right? It is until you look at all of the dynamic allocations you have to make sure are cleaned up. Memory management is one of the hardest things to get right in C++, and one of the best ways to manage memory management is through Resource Allocation Is Initialization or RAII. std::vector and std::unique_ptr are fabulous examples of RAII in action.
vector is a dynamic array all nicely wrapped up inside a class that handles virtually every aspect of list management right down to adding, removing, resizing, and making sure everything gets cleaned up. unique_ptr is a Smart Pointer that ensures exactly one owner of a resource, and this owner will clean up the resource when it is destroyed. The result, std::vector<std::unique_ptr<Student>> will allow you to add, remove, access, and move any Students without any direct intervention. This allows you to write simpler code. Simpler code is less likely to have bugs. Fewer bugs means more leisure time and happier clients. Everybody wins.
Suppose you already have a collection, for example a linked list of Students which is in order by Student ID. You want to sort them by Student last name. Instead of changing your linked list, or messing up its order, you just allocate an array of pointers and sort that. Your original list remains intact but you can do fast binary searches by last name using your array.

How to manage millions of game objects with a Slot Map / Object Pool pattern in C++?

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.

C++: Vector of Pointers to Objects from another Vector

I have two classes, similar to this:
class A
{
public:
B* ptr1;
}
class B
{
public:
std::vector<A*> list;
}
In the main implementation, I'm doing something like this:
int main() {
// there are a lot more A objects than B objects, i.e. listOfA.size() >>> listOfB.size()
std::vector<A> listOfA;
std::vector<B> listOfB;
while (//some loop)
{
listOfB[jj].list.push_back( &(listofA[ii]) );
listOfA[ii].ptr1 = &( listOfB[jj] );
}
} // int main end
Basically something like this. A lot of A objects are assigned to one B object, and these A objects are stored in that pointer vector as pointers. Additionally, each of these A objects get a pointer to the B object they belong to. For the context, I'm basically doing an Connected Components Algorithm with run-length-encoding (for image segmentation), where class A are the line segments and class B are the final objects in the image.
So, the pointers of the vector in class B all point to Objects which are stored in a regular vector. These objects should be deleted when the regular vector goes out of scope, right? I've read that a vector of pointer like in class B usually requires writing a manual destructor, but this shouldn't be the case here, I think...
The reason why I'm asking is, of course, because my code keeps crashing. I'm using an Asus Xtion Pro camera to get the images and then am performing the algorithm on every image. Weird thing is, the program crashes whenever I shake the camera a bit harder. When the camera is stationary or moved only a little or slowly, nothing happens. Also, when I use a different algorithm (also connected components, but without run-length-encoding and also doesn't use pointers), nothing crashes, no matter how much I shake the camera. Also, in Debug mode (which ran much slower than the Release mode), nothing crashed either.
I tried making a destructor for the pointer vector in class B, but it resulted in a "block is valid" error, so I guess it deleted something twice.
I also tried replacing every pointer wih a c++11 std::shared_ptr, but that only produced very irregular behaviour and the code still crashed when I shaked the camera.
I basically just want to know if in terms of memory leaking and pointer handling, the code shown above seems fine or if there are mistakes in the code which could lead to crashes.
EDIT (SOLVED): The solution (see the accepted answer) was to ensure that the vector 'listOfB' doesn't get resized during run-time, for example by using 'reserve()' to reserve enough space for it. After doing this, everything worked fine! Apparently it worked, because if the vector 'listOfB' gets resized (by push_back()), the internal memory adresses of the B instances in it are also changed, causing the pointers in the A instances (which point to B instances) to now point to the wrong adresses - and thus resulting in trouble, which lead to the crash.
About the camera shaking, apparently, shaking the camera resulted in very blurry pictures with lot of elements to segment, thus increasing the number of objects (i.e., resulting in higher size required for listOfB). So, mystery solved! Thanks a lot! :-)
I think the design is broken. listofB will grow (you do push_backs) and re-allocate its internal data array, invalidating all addresses stored in the ptrs of the A instances. The usual algorithm will grow the data size by a factor of 2 which may explain that you are good for a while if not too much data arrives. Also, as long as the memory of the old data is still in the address space of the program (especially if it is on the same memory page, for example because the new data fits in it as well), the program may not crash accessing it and just retrieve old data.
On a more constructive note: Your solution will work if you know the maximum elements in advance, which may be hard (think you get a 4k camera next year ;-)). In that case you can, by the way, just take a simple static array anyway.
Perhaps you could also use a std::map to store A objects instead of a simple vector listofA. Each A object would need a unique ID of some sort (static counter in A in the easiest case) to use as a key into the map. Bs would store keys, not addresses of As.
Assuming you have not made a mistake in how you build your network you should be fine. You would have to post more code to assess that. Also you can not use either of the vectors after you change one of them because if they reallocate their members all pointers pointing to them are invalidated. But using raw pointers to managed objects is the correct way to build networks.
By managed objects I mean objects whose lifetime is guaranteed to last longer than the network and whose memory will be automatically released. So they should be elements of a container or objects managed by some kind of smart pointer.
However it sounds like you have a hardware problem.

Should the objects initialized and stored in another class be dynamically/statically allocated?

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.