How do I prevent adding an object in multiple vectors? - c++

There are some objects that are Drawable and some that are Movable.
All movable objects are dawable.
I store all the drawable objects in a vector called drawables and movable objects in a vector called movables.
I also have vectors ships and bullets which contain objects of type Ship and Bullet respectively.
Ship and Bullet both are Movable
Here's the structure of the classes:
class Drawable {
public:
void draw();
};
class Movable : public Drawable {
public:
void move();
}
class Ship : public Movable {
public:
Ship();
}
class Bullet : public Movable {
public:
Bullet();
}
The vectors are declared as follows:
std::vector<Drawable*> drawables;
std::vector<Movable*> movables;
std::vector<Ship*> ships;
std::vector<Bullet*> bullets;
The thing is, that each time I create a Ship I have to add it in all the vectors i.e.
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
I have created separate drawables and movables vectors since I have a draw() function which calls the draw() method of all objects in the drawables vector. Similarly, I have a move() function which calls the move() method of all objects in the movables vector.
My question is, how do I change the structure to prevent adding the same thing in different vectors. I also need to remove objects from all the vectors once it's purpose is done.
For example, once the bullet hits someone or moves out of the screen, then I'll have to remove it from the vectors drawables, movables and bullets after searching it in all three vectors.
It seems like I'm not using the correct approach for storing these objects. Please suggest an alternative.
This seems more like a software engineering question than a coding question. Please migrate the question to other forum if necessary.

Assuming you are using a reasonably modern compiler, this is exactly why shared_ptr exists.
The problem is that you have no idea which vector owns the object, so you don't know which one to delete. shared_ptr takes are of this for you: it manages the lifetime of the object, and will delete it once the last reference to the object is destroyed.
To create a new Ship, you could do something like this:
auto ship = std::make_shared<Ship>();
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
At this point ship has 4 references (one for each vector, and the ship variable itself). It will automatically be deleted once it has been removed from all three vectors and the local variable goes out of scope.

If you are going to maintain a container of (pointers to) all objects of a certain type, you may want to take a RAII approach. Have the object's constructor add to the container, and the destructor remove from it. You'd also want to make sure nothing else modifies the container, so it should be a private (static) member of your class, with a public method to provide read-only access.
Even better, move this logic into its own class, so it can be re-used. This would also allow your existing containers to remain focused on what they currently do. They would just need a new data member of the helper class type.
To ease removals, I would consider using a list instead of a vector. Also, it might be worth using reference_wrapper instead of pointers. A pointer can have a null value. While you can document that the container will have no null pointers, a reference_wrapper conveys this with no additional documentation.
To get you started, here is the start of a helper class template you could use.
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};
Names are often tough to come by. I named this template based on getting something to iterate over, for example: All<Movable>::list().

Related

Use a unique_ptr and return a reference or should I use a shared_ptr and make copies if needed

I have a cache that stores unique ptrs of objects in an unordered map and returns a reference of the object for users of the cache. It works as it should, storing the objects until they go out of scope.
The cache is implemented as follows:
store objects in cache:
template<typename T>
template<typename... Args>
void ResourceCache<T>::add(const std::string& name, Args... args)
{
m_cache->try_emplace(name, std::make_unique<T>(args...));
}
get object from cache:
template<typename T>
T& ResourceCache<T>::getCachedElement(const std::string& name) const
{
auto it = m_cache->find(name);
if(it != m_cache->end())
return *it->second;
throw "resource not found";
}
But now I walk in to the problem that a reference is not always what I would like to get from the cache, per example:
I have the following object:
class GameObject
{
public:
void translate(const cheetah::Vector3f& position);
protected:
Quaternion m_rotation;
Vector3f m_position;
};
lets say I want the object to have a Texture, currently the only way for me would be to add a member reference
Texture& m_texture
This would result in me having to either
Pass a Texture to the constructor for each object, even if they dont need a texture.
Create a TexturedGameObject that inherits from the GameObject and adds a Texture member and constructor.
Use shared pointers instead of unique pointers and be able to return a copy
Now my question is
What would be seen as best practice in this specific situation? should I use one of the above options or have I missed an even better option?
I know my question is not the most specific but I am learning c++ by myself and it would be nice to get someone elses view on this.
Assuming ResourceCache holds Texture, here's my thoughts. There does not seem to be one best solution in general.
Pass a Texture to the constructor for each object, even if they dont need a texture.
You would need to pass a dummy object so if you want to go with this way, I would suggest keeping it as a raw pointer instead
By doing this you can check if it really has a pointer or not since it can be nullptr
NOTE Either reference or pointer, you should make sure that ResourceCache outlives all GameObject - the lifetimes must be managed manually
Create a TexturedGameObject that inherits from the GameObject and adds a Texture member and constructor.
This could be an option but I think this is more a design issue
Use shared pointers instead of unique pointers and be able to return a copy
This would work fine
Safe (no issues like double-deletion/dangling-pointers)
Shared pointer has overhead

C++ and standard containers: memory addresses of members

I am currently having some trouble with my understanding of the memory management in standard containers, especially std::vector.
It is clear to me that std::vector will resize after adding an element to it if there is not enough space reserved, therefore moving each element and changing the addresses in memory. My question is now: what happens to the element's member variables?
My problem is based on the idea that for my game engine I am currently managing scenes in a std::vector. The scenes are managed by a Scene manager class that contains a std::vector of Scenes. Adding of scenes looks like this:
std::vector<Scene> scenes;
Scene* active;
...
Scene scene;
scenes.emplace_back(scene);
active = &scenes.back();
The scenes are stack-allocated and will be thrown away after leaving the method. For exposing the currently added scene to the outside I am storing a pointer to the back of the std::vector which is the newly inserted element.
Scenes contain various members, for example an instance of the Light class. I also expose pointers to those elements to the outside for various reasons. My problem was that I tried to use those pointers in the constructor of the Scene which got constructed in the Scene manager. After adding the object to the std::vector a new object seems to be constructed even if the Scene constructor doesn't seem to be called. The "active" member now contains an different memory address than the actual Scene object I allocated before. As the vector needs to resize I am clear with that I think.
But what happens to the members of the scene? The original Scene will be destructed, the active element got another memory address. That means it points to an whole new element because of the internal resize and that new element has new members and are in my case those I want to work with.
Am I right with my understanding?
My second question includes how I should handle situations like that where I want to expose pointers to members of objects stored in a std::vector with unknown size. My current method of choice works just fine but I am not sure if it is the right way to do:
In the Scene class there is an onActivate event method which will just be called after the whole resizing and getting the inserted element of the vector has finished. When I switch the active pointer that method will be called, too. That method takes the pointers to the members of the scene and passes them around. It looks something like that:
void postConstruct() {
std::cout << "postConstruct: " << &el << std::endl;
}
And will be called at the right place in the Scene manager which currently is a friend to the Scene class because those events should not be exposed to the outer world.
active->postConstruct();
Is this the right way to go?
In case the std::vector is resized, the elements will be either moved using element's move constructor if the move constructor is declared as noexcept or it would be copied using element's copy constructor to the newly allocated position.
Whether the member pointers will be same after reallocation will depend upon how the move constructor or copy constructor is implemented for the element being inserted.
I would suggest using index than Scene* to access the elements in std::vector or use std::list if you want to use Scene*
When a vector is expanded, all iterators, pointers and references to elements become invalid. The only defined thing you can do with an invalid pointer or iterator is overwrite it with another value, and there is nothing you can do with an invalid reference. Even comparing the value to some other value makes your program ill-formed.
When you do
Scene scene;
scenes.emplace_back(scene);
active = &scenes.back();
You have two Scene objects. One is a local variable, the other is in the vector, and was copied from scene. I'm not sure that you are aware of this distinction, you probably only want one Scene object. Either all Scenes live in scenes, or you change it to be a std::vector<Scene *>, or a std::vector<std::reference_wrapper<Scene>>. If you do the latter, make sure to remove values before they are destroyed.
The language provided copy constructor will simply copy the value of each member, which in the case of pointers, will tend to be the wrong thing. You can explicitly define a copy constructor for Scene to control exactly what happens, e.g. "deep copy" pointer members.
class Copyable
{
int* ptr;
public:
Copyable() : ptr(new int) {}
~Copyable() { delete ptr; }
Copyable(const Copyable & other) : ptr(new int(*other.ptr)) {} // deep copy
Copyable& operator=(const Copyable & other)
{
*ptr = *other.ptr;
return *this;
}
};
Alternatively, you can prohibit the copying of Scenes by defining the copy constructor as = deleted
class UnCopyable
{
int* ptr;
public:
UnCopyable() : ptr(new int) {}
~UnCopyable() { delete ptr; }
UnCopyable(const UnCopyable & other) = delete;
UnCopyable& operator=(const UnCopyable & other) = delete;
};

Vector of Reference Objects?

I have a class setup analogous to this:
class BlimpBase{
public:
virtual ~BlimpBase();
private:
virtual void lift()const = 0;
};
class Blimp: protected BlimpBase{
void lift()const;
};
class BlimpCarrier{
public:
add_blimp(BlimpBase& blimp);
private:
std::vector<BlimpBase* blimp> blimps;
};
As you can see, I have a set of polymorphic blimp classes and I am trying to store then as "references" in the vector by using pointers (I realize you can't store references in vectors, I just don't know how else to describe them). The problem is that most of these objects are allocated on the stack as class members, but I want to add them to this vector so that I can directly modify them (copies won't do). The problem with keeping pointers to these objects is that if these objects go out of scope before the BlimpCarrier does (since they are on the stack), I will have a dangling pointer. I looked into std::unique_ptr and std::shared_ptr, but I don't think I can use them here...
Assuming you CAN change where they are allocated on the stack, or the classes that have them as members, then you can try this with std::weak_ptr:
class BlimpCarrier{
public:
add_blimp(std::shared_ptr<BlimpBase>& blimp_ptr)
{
blimps.push_back(blimp_ptr);
}
private:
std::vector<std::weak_ptr<BlimpBase>> blimps;
};
BlimpCarrier globalCarrier;
void foo()
{
std::shared_ptr<BlimpBase> instance(new BlimpSubClass());
globalCarrier.add_blimp(instance);
}
You need an extra step, that when you traverse the vector that you check that the weak_ptr objects have been "Expired" or not, and then remove them yourself from the vector. I'd actually suggest using a std::list instead for a linked list implementation for this type of thing. See cppreference.com for a good example for how to correctly and safely use weak_ptr.

How to store different data types in one list? (C++)

I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".

Classes, constructor and pointer class members

I'm a bit confused about the object references. Please check the examples below:
class ListHandler {
public:
ListHandler(vector<int> &list);
private:
vector<int> list;
}
ListHandler::ListHandler(vector<int> &list) {
this->list = list;
}
Because of the internal
vector<int> list;
definition, here I would be wasting memory right? So the right one would be:
class ListHandler {
public:
ListHandler(vector<int>* list);
private:
vector<int>* list;
}
ListHandler::ListHandler(vector<int>* list) {
this->list = list;
}
ListHandler::~ListHandler() {
delete list;
}
Basically all I want is to create a vector and pass to ListHandler. This vector will not be used anywhere else than the ListHandler itself so I'm expecting ListHandler to do all the other things and cleanup etc. stuff.
It depends on whether you want to share the underyling vector or not. In general, I think it is a good practice to avoid sharing wherever possible, since it removes the question of object ownership. Without sharing:
class ListHandler
{
public:
ListHandler(const std::vector<int>& list) : _list(list) {}
~ListHandler(){}
private:
std::vector<int> _list;
};
Note that, unlike in your example, I make it const since the original will not be modified. If, however, we want to hang on to and share the same underlying object, then we could use something like this:
class ListHandler
{
public:
ListHandler(std::vector<int>& list) : _list(&list) {}
~ListHandler(){}
private:
std::vector<int>* _list;
};
Note that in this case, I choose to leave the caller as the owner of the object (so it is the caller's responsiblity to ensure that the list is around for the lifetime of the list handler object and that the list is later deallocated). Your example, in which you take over the ownership is also a possibility:
class ListHandler
{
public:
ListHandler(std::vector<int>* list) : _list(list) {}
ListHandler(const ListHandler& o) : _list(new std::vector<int>(o._list)) {}
~ListHandler(){ delete _list; _list=0; }
ListHandler& swap(ListHandler& o){ std::swap(_list,o._list); return *this; }
ListHandler& operator=(const ListHandler& o){ ListHandler cpy(o); return swap(cpy); }
private:
std::vector<int>* _list;
};
While the above is certainly possible, I personally don't like it... I find it confusing for an object that isn't simply a smart pointer class to acquire ownership of a pointer to another object. If I were doing that, I would make it more explicit by wrapping the std::vector in a smart pointer container as in:
class ListHandler
{
public:
ListHandler(const boost::shared_ptr< std::vector<int> >& list) : _list(list) {}
~ListHandler(){}
private:
boost::shared_ptr< std::vector<int> > _list;
};
I find the above much clearer in communicating the ownership. However, all these different ways of passing along the list are acceptable... just make sure users know who will own what.
The first example isn't necessarily wasting memory, its just making a copy of the entire vector at the "this->list = list;" line (which could be what you want, depends on the context). That is because the operator= method on the vector is called at that point which for vector makes a full copy of itself and all its contents.
The second example definitely isn't making a copy of the vector, merely assigning a memory address. Though the caller of the ListHandler contructor better realize that ListHandler is taking over control of the pointer, since it will end up deallocating the memory in the end.
It depends on whether the caller expects to keep using their list (in which case you better not delete it, and need to worry about it changing when you least expect), and whether the caller is going to destroy it (in which case you better not keep a pointer to it).
If the documentation of your class is that the caller allocates a list with new and then turns ownership over to your class when calling your constructor, then keeping the pointer is fine (but use auto_ptr so you don't have to write "delete list" yourself and worry about exception safety).
It all depends what you want, and what policies you can ensure. There is nothing "wrong" with your first example (though I would avoid explicitly using this-> by choosing different names). It makes a copy of the vector, and that may be the right thing to do. It may be the safest thing to do.
But it looks like you would like to reuse the same vector. If the list is guaranteed to outlive any ListHandler, you can use a reference instead of a pointer. The trick is that the reference member variable must be initialized in an initialization list in the constructor, like so:
class ListHandler
{
public:
ListHandler(const vector<int> &list)
: list_m(list)
{
}
private:
vector<int>& list_m;
};
The initialization list is the bit after the colon, but before the body.
However, this is not equivalent to your second example, which using pointer and calls delete in its destructor. That is a third way, in which the ListHandler assumes ownership of the list. But the code comes with dangers, because by calling delete it assumes the list was allocated with new. One way to clarify this policy is by using a naming convention (such as an "adopt" prefix) that identifies the change of ownership:
ListHandler::ListHandler(vector<int> *adoptList)
: list_m(adoptList)
{
}
(This is the same as yours, except for the name change, and the use of an initialization list.)
So now we have seen three choices:
Copy the list.
Keep a reference to a list that someone else owns.
Assume ownership of a list that someone created with new.
There are still more choices, such as smart pointers that do reference counting.
There's no single "right way." Your second example would be very poor style, however, because the ListHandler acquires ownership of the vector when it is constructed. Every new should be closely paired with its delete if at all possible — seriously, that is a very high priority.
If the vector lives as long as the ListHandler, it might as well live inside the ListHandler. It doesn't take up any less space if you put it on the heap. Indeed, the heap adds some overhead. So this is not a job for new at all.
You might also consider
ListHandler::ListHandler(vector<int> &list) {
this->list.swap( list );
}
if you want the initializer list to be cleared and avoid the time and memory overhead of copying the vector's contents.