Objects referenced in multiple locations - c++

I am trying to figure out how to manage items in my program. I want to have a unified inventory system that knows where every item is. Then have container objects that actually hold the inventoried items, and have everything locate-able by container id.
My thought was to have items held inside the containers inside boost::ptr_vetors, and then hold a pointer (probably the same one) inside a hash table inside the inventory object, now shifting things around in terms of the inventory is easy that just changing a single value, and moving things from containerX to containerY is just a matter of removing from one pointer vector, and passing it to the other container, or doing all the work in one container, or another.
The problem that I am having trouble considering is when it comes time to get all the stuff out. I have only really ever dealt with having a pointer/object held in one place at a time not multiple, and I know that if I try to delete something that has already been deleted it will cause a crash at the least. The first thing that comes to mind is to remove all the references from the containers, and still have it reside in the inventory, and then step through, and delete the inventory. Is this feasible, or am I not considering this right, and need to reconsider this? then what if I only need to remove a single thing (keep the rest)?
I am concerned about de-validating the pointers in either case.

Boost::ptr_vector assumes ownership of the object when you pass it in. When you remove an object from that vector it will be automatically deleted. You can remove items without deleting them however by using the built in auto_type (see the farm yard example for usage).
This means that you should really only have an item in one ptr_vector at a time. However your idea of having items in a ptr_vector and then having the ptr_vector be owned by your inventory object (which is another ptr_vector) should work. I have never done that but it should be fine.
In order to delete a single object you just look it up using a container_id and an item_id, and then remove it from the item-level ptr_vector. In order to delete a container, just remove it from the inventory. It will destruct anything that it contains at that point.
If you want to remove them without deletion use the auto_type to remove them safely. You can release them from the auto_type and do as you please if you want to using raw pointers to objects.

There are a few ways to do this.
Use boost::shared_ptr or std::shared_ptr with the standard vector. That way you do not
have to worry about deleting and memory is freed incrementally
whenever no pointer references the object. This can be useful if you need to destroy specific objects frequently and requires the least amount of code. The downside is storage
overhead if most objects are never destroyed apart from the rest and you have a lot of objects. And, depending on where you remove the object, it can still reside in the inventory without a container or vice versa.
Give the containers responsibility for destruction and deindexing from the inventories by deriving them or wrapping them in another class. Since each object's pointer only appears in one container as described by you, only inventories may hold extra pointers. Hence whenever an object is to be removed, the container will have to look up the inventories to remove the pointer to the object it is about to destroy. The overhead is the bookkeeping of the inventories.
Use a memory pool that is a container that stores pointers to all objects and is responsible for their destruction when itself is destroyed. The memory pool can be a boost::ptr_vector while the other containers are standard vectors. This effective for frequent adding and querying objects in the system. The downside is that the memory pool must outlive your containers and inventories. Otherwise it has to do bookkeeping like in (2) if individual objects need to be destroyed apart from the rest.

Related

C++ Library free pointer

I am creating a simple C++ MIDI library and I ran into a small problem. Currently, I have implemented everything but the reading of files. Internally, I have a std::vector with raw, dynamically allocated pointers (with the new() keyword) of events, which is an abstract class and can therefore not be instantiated. Now that I've finally started on the reading part, there is a slight problem. I will have to allocate the objects myself and later free them too. This creates problems though, since the user of the library may include events in between or append them. This will mean that there are dynamic pointers that have been created elsewhere in my std::vector, which makes freeing a difficult question.
To make this question more general, I was wondering what I should do with pointers provided by the user of the library. What should I do with them? I was thinking one of the points on the list:
Free all pointers and note that pointers given to the class do not have to be freed any more (which seems strange and counter-intuitive, since the new is matched with the delete in a completely different setting)
Maintain a list of pointers provided by the user and simply skip any pointer in that list (probably not really a solution, because the entire list would have to be checked every time)
Making the creation of events only available with the class, so the user cannot create pointers with the new keyword but only by letting the handling class allocate them.
Forcing the use of shared pointers and using them exclusively in my code, so that they will be automatically freed when they go out of scope.
Maintaining a list of your own pointers and only freeing them, and let the user given pointers go out of scope / they will have to clean them up themselves.
...? (something I have maybe not thought of?)
So please, tell me what is customary in a situation like this, where the user of the library provides pointers which is added to a list maintained by you and then the list goes out of scope, while you have your own pointers mixed with theirs.
Thanks in advance!
Pick a consistent policy. Don't choose any of those options that lead to you have to destroy some objects in some places and other objects in other places. Especially not those approaches in which the user is responsible for destroying some objects but not others. Ownership should be handled uniformly.
My first suggestion would be to avoid dynamically allocating objects completely. Can you not store a std::vector<Event> and pass Events by value to and from your library? Then the user can happily not care about the ownership of objects, but they can choose to dynamically allocate them if they wish.
If you really need to dynamically allocate objects, I suggest that you always wrap them in smart pointers so that ownership is managed automatically. If, for example, you are allocating some object on behalf of the user, the standard interface for this is something like:
std::unique_ptr<Object> createObject();
If, on the other hand, your library has some internal dynamically allocated that it needs to share with the user, return a std::shared_ptr.

The "this" pointer and containers

For my game I have built a small framework which among other things has:
Entities that own components.
Systems that hold pointers to the entities.
An Engine that owns the systems.
An EntityManager that owns the entities.
Every time I add a Component, the Entity passes it's "this" pointer to the Systems through an Engine pointer that it holds and they decide whether to register it or ignore it.
Now, since the Entities are elements of the EntityManager's container, am I right in assuming that if an insert operation to it causes shifts or reallocation, the systems won't hold valid pointers any more?
If so, what's a good container that can be used to prevent this from happening? If I understand things correctly this is similar to what happens with iterators and the same rules should apply when requiring non-invalidation with insertion.
If you store a vector of entities and then just store their iterators to access them: yes, a reallocation might invalidate all your data.
The suggested way is to store a vector of pointers (if you need memory collection capabilities you might want to go for a vector of smart pointers). This way you will be sure that the pointers are valid (assuming nothing else touched the objects) at every insertion/deletion regardless of the reallocation of the container's space.
From the question isn't clear but a word of advice if you're just storing objects in your containers instead of pointers: when inserting elements into a container like with
std::vector<T>::push_back()
you're storing a copy of the object. This is usually undesirable since brings additional copy overhead and might create problems if things aren't properly set up. See "shallow copies" and "deep copies" to learn more about this problem.
Your pointer value will only change if a relocation of the actual value happens.
This is the case where you manipulate arrays of objects instead of arrays of pointers to these objects. You should definitely not do the former.
I would suggest using standard collections like std::array or std::vector to manage the objects. With those, and provided you have instanciated the objects on the heap (read: with new), you won't have to worry about the value of this.

Memory allocation of values in a std::map

I've had some experience in C++ from school works. I've learned, among other things, that objects should be stored in a container (vector, map, etc) as pointers. The main reason being that we need the use of the new-operator, along with a copy constructor, in order to create a copy on the heap (otherwise called dynamic memory) of the object. This method also necessitates defining a destructor.
However, from what I've read since then, it seems that STL containers already store the values they contain on the heap. Thus, if I were to store my objects as values, a copy (using the copy constructor) would be made on the heap anyway, and there would be no need to define a destructor. All in all, a copy on the heap would be made anyway???
Also, if(true), then the only other reason I can think of for storing objects using pointers would be to alleviate resource needs for copying the container, as pointers are easier to copy than whole objects. However, this would require the use of std::shared_ptr instead of regular pointers, since you don't want elements in the copied container to be deleted when the original container is destroyed. This method would also alleviate the need for defining a destructor, wouldn't it?
Edit : The destructor to be defined would be for the class using the container, not for the class of the objects stored.
Edit 2 : I guess a more precise question would be : "Does it make a difference to store objects as pointers using the new-operator, as opposed to plain values, on a memory and resources used standpoint?"
The main reason to avoid storing full objects in containers (rather than pointers) is because copying or moving those objects is expensive. In that case, the recommended alternative is to store smart pointers in the container.
So...
vector<something_t> ................. Usually perfectly OK
vector<shared_ptr<something_t>> ..... Preferred if you want pointers
vector<something_t*> ................ Usually best avoided
The problem with raw pointers is that, when a raw pointer disappears, the object it points to hangs around causing memory and resource leaks - unless you've explicitly deleted it. C++ doesn't have garbage collection, and when a pointer is discarded, there's no way to know if other pointers may still be pointing to that object.
Raw pointers are a low-level tool - mostly used to write libraries such as vector and shared_ptr. Smart pointers are a high-level tool.
However, particularly with C++11 move semantics, the costs of moving items around in a vector is normally very small even for huge objects. For example, a vector<string> is fine even if all the strings are megabytes long. You mostly worry about the cost of moving objects if sizeof(classname) is big - if the object holds lots of data inside itself rather than in separate heap-allocated memory.
Even then, you don't always worry about the cost of moving objects. It doesn't matter that moving an object is expensive if you never move it. For example, a map doesn't need to move items around much. When you insert and delete items, the nodes (and contained items) stay where they are, it's just the pointers that link the nodes that change.

A std::vector of pointers?

Here is what I'm trying to do. I have a std::vector with a certain number of elements, it can grow but not shrink. The thing is that its sort of cell based so there may not be anything at that position. Instead of creating an empty object and wasting memory, I thought of instead just NULLing that cell in the std::vector. The issue is that how do I get pointers in there without needing to manage my memory? How can I take advantage of not having to do new and keep track of the pointers?
How large are the objects and how sparse do you anticipate the vector will be? If the objects are not large or if there aren't many holes, the cost of having a few "empty" objects may be lower than the cost of having to dynamically allocate your objects and manage pointers to them.
That said, if you do want to store pointers in the vector, you'll want to use a vector of smart pointers (e.g., a vector<shared_ptr<T>>) or a container designed to own pointers (e.g., Boost's ptr_vector<T>).
If you're going to use pointers something will need to manage the memory.
It sounds like the best solution for you would be to use boost::optional. I believe it has exactly the semantics that you are looking for. (http://www.boost.org/doc/libs/1_39_0/libs/optional/doc/html/index.html).
Actually, after I wrote this, I realized that your use case(e.g. expensive default constructor) is used by the boost::optional docs: http://www.boost.org/doc/libs/1_39_0/libs/optional/doc/html/boost_optional/examples.html#boost_optional.examples.bypassing_expensive_unnecessary_default_construction
You can use a deque to hold an ever-increasing number of objects, and use your vector to hold pointers to the objects. The deque won't invalidate pointers to existing objects it holds if you only add new objects to the end of it. This is far less overhead than allocating each object separately. Just ensure that the deque is destroyed after or at the same time as the vector so you don't create dangling pointers.
However, based on the size of the 3-D array you mentioned in another answer's comment, you may have difficulty storing that many pointers. You might want to look into a sparse array implementation so that you mainly use memory for the portions of the array where you have non-null pointers.
You could use a smart pointer. For example boost::shared_ptr.
The issue is that how do I get pointers in there without needing to manage my memory?
You can do certainly do this using the shared_ptr or other similar techniques mentioned here. But in near future you will come across some problem where you will have to manage your own memory. So please get yourself comfortable with the pointer concept.
Normally if you see in big servers the memory management of object itself is considered as a responsibility and specially for this purpose you will create a class. This is known as pool. Whenever you need an object you ask the pool to give you the object and whenever you are done with the object you tell the pool that I am done. Now it is the responsibility of the pool to see what can be done with that object.
But the basic idea is your main program still deals with pointers but do not care about the memory. There is some other object who cares about it.

Should boost::ptr_vector be used in place std::vector all of the time?

Just a conceptual question that I've been running into. In my current project it feels like I am over-using the boost smart_ptr and ptr_container libraries. I was creating boost::ptr_vectors
in many different objects and calling the transfer() method to move certain pointers from one boost::ptr_vector to another.
It is my understanding that it is important to clearly show ownership of heap allocated objects.
My question is, would it be desirable to use these boost libraries to create heap-allocated members that belong to an object but then use normal pointers to these members via get() when doing any processing.
For example...
A game might have a collection of Tiles that belong to it. It might make sense to create these tiles in a boost::ptr_vector. When the game is over these tiles should be automatically freed.
However if I want to put these Tiles in a Bag object temporarily, should I create another boost::ptr_vector in the bag and transfer the Game's Tiles to the Bag via transfer() or
should I create a std::vector<Tile*> where the Tiles*'s reference the Tiles
in the Game and pass that to the Bag?
Thanks.
**Edit
I should point out that in my example The Game would have a Bag object as a member. The Bag would only be filled with Tiles the game owns. So the Bag would not exist without the Game.
You should only use owning smart pointers and pointer containers where there's clear transfer of ownership. It doesn't matter if the object is temporary or not - all that matters is whether it has ownership or not (and, therefore, whether the previous owner relinquishes ownership).
If you create a temporary vector of pointers just to pass it to some other function, and the original ptr_vector still references all those objects, there's no ownership transfer, and therefore you should use plain vector for the temporary object - just as you'd use a raw pointer to pass a single object from ptr_vector to a function that takes a pointer, but doesn't store it anywhere.
In my experience, there are three main ownership patterns that crop up. I will call them tree, DAG and graph.
The most common is a tree. The parent owns its children, which in turn owns its children and so on. auto_ptr, scoped_ptr, bare pointers and the boost ptr_x classes are what you typically see here. In my opinion, bare pointers should generally be avoided as they convey no ownership semantics at all.
The second most common is the DAG. This means you can have shared ownership. The children a parent owns may also be the children of other children the parent owns. The TR1 and boost shared_ptr template is the main actor here. Reference counting is a viable strategy when you have no cycles.
The third most common is the full graph. This means that you can have cycles. There are some strategies for breaking those cycles and returning to a DAG at the cost of some possible sources of error. These are generally represented by TR1 or boost's weak_ptr template.
The full graph that can't be broken down into a DAG using weak_ptr is a problem that can't easily be solved in C++. The only good handlers are garbage collection schemes. They are also the most general, capable of handling the other two schemes quite well as well. But their generality comes at a cost.
In my opinion, you can't overuse the ptr_x container classes or auto_ptr unless you really should be using containers of objects instead of containers of pointers. shared_ptr can be overused. Think carefully about whether or not you really need a DAG.
Of course I think people should just be using containers of scope_ptrs instead of the boost ptr_x classes, but that's going to have to wait for C++0x. :-(
Most likely, the solution you're looking for is
std::vector<Tile>
There's no need for pointers most of the time. The vector already takes care of memory managements of the contained objects. The tiles are owned by the game, aren't they? The way to make that explicit is to put the objects themselves in the game class -- the only cases where you typically need pointers and dynamically allocated individual objects is if you need 1) polymorphism, or 2) shared ownership.
But pointers should be the exception, not the rule.
boost::ptr_vector only serves to improve the semantics of using vectors of pointers. If, in your example, the original array could be destroyed while the temporary set of vectors is in use, then you should definitely be using a vector of shared_ptrs to prevent them from being deleted while still in use. If not, then a plain old vector of pointers may be appropriate. Whether you choose std::vector or boost::ptr_vector doesn't really matter, except in how nice the code that uses the vector looks.
In your game tiles example, my first instinct would be to create a vector<Tile>, not a vector<Tile*> or a ptr_vector. Then use pointers to the tiles as you please, without worrying about ownership at all, provided that the objects which hold the pointers don't outlive the vector of tiles. You've said it's only destroyed when the game ends, so that shouldn't be difficult.
Of course there may be reasons this is not possible, for instance because Tile is a polymorphic base class, and the tiles themselves are not all of the same class. But this is C++, not Java, and not every problem always needs dynamic polymorphism. But even if you do really need pointers, you can still make copies of those pointers without any ownership semantics, provided that the scope and storage duration of the objects pointed to is understood to be wider than the scope and duration of use of the pointer:
int main() {
vector<Tile*> v;
// fill in v, perhaps with heap objects, perhaps with stack objects.
runGame(v);
}
void runGame(const vector<Tile*> &v) {
Tile *firsttile = v[0];
vector<Tile*> eventiles;
eventiles.push_back(v[2]);
eventiles.push_back(v[4]);
// and so on. No need to worry about ownership,
// just as long as I don't keep any pointers beyond return.
// It's my caller's problem to track and free heap objects, if any.
}
If the Game owns the tiles then the Game is responcable for there deltion.
It sounds like the bag never actually ownes the objects so it should not be responcable for deleting them. Thus I would use ptr_vector within the Game object. But use a std::vector in the bag.
Note: I would never let anybody using the bag retrieve a pointer to a tile from the bag. They should only be able to retrieve a referenceto the tile from the bag.
If Tiles are placed in the Bag and someone steals the Bag you lose all tiles. Therefore Tiles, althought temporarly, but they belong to the Bag for a short time. You should transfer ownership here, I suppose.
But the better opinion would be not to mess with ownership, because I don't see why it's needed in this particular case. If there's something behind the scene, go on, make your choice.
I agree that using vector instead of jumping right into heap-allocated T is a good instinct, but I can easily see Tile being a type for while copy construction is expensive, which might preclude vector's growth strategy being practical. Of course, that might be best solved with a list, not a vector...