Since you are explicitly stating you want to improve your C++, I am going to recommend you start using Boost. This can help you with your problem in three different ways:
Using a shared_ptr
Using a shared_ptr
could declare your vector like this:
std::vector< boost::shared_ptr< ObjectBase > > object_list;
And use it like this:
typedef std::vector< boost::shared_ptr< ObjectBase > >::iterator ObjectIterator;
for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
(*it)->draw(view);
This would give you polymorphism and would be used just like it was a normal vector of pointers, but the shared_ptr
would do the memory-management for you, destroying the object when the last shared_ptr
referencing it is destroyed.
Note about C++11: In C++11 shared_ptr
became part of the standard as std::shared_ptr
, so Boost is no longer required for this approach. However, unless you really need shared ownership, it is recommended you use std::unique_ptr
, which was newly introduced in C++11.
Using a ptr_vector
Using a ptr_vector
you would do it like this:
boost::ptr_vector< ObjectBase > object_list;
And use it like this:
typedef boost::ptr_vector< ObjectBase >::iterator ObjectIterator;
for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
(*it)->draw(view);
This would again be used like a normal vector of pointers, but this time the ptr_vector
manages the lifetime of your objects. The difference to the first approach is, that here your objects get destroyed when the vector gets destroyed, whereas above they may live longer than the container, if other shared_ptr
s referencing them exist.
Using a reference_wrapper
Using a reference_wrapper
you would declare it like this:
std::vector< boost::reference_wrapper< ObjectBase > > object_list;
And then use it like this:
typedef std::vector< boost::reference_wrapper< ObjectBase > >::iterator
ObjectIterator;
for ( ObjectIterator it = object_list.begin(); it != object_list.end(); it++ )
it->draw(view);
Notice that you do not have to dereference the iterator first as in the above approaches. This does however only work if the lifetime of your objects is managed elsewhere and is guaranteed to be longer than that of the vector
.
Note about C++11: reference_wrapper
has also been standardized in C++11 and is now usable as std::reference_wrapper
without Boost.
As pointed out in Maciej Hs answer, your first approach results in object slicing. In general you may want to look into iterators when using containers.
Best Answer
You should use a vector of objects whenever possible; but in your case it isn't possible.
Containers of pointers let you avoid the slicing problem. But then you have to call delete on each element, like you are doing. That's annoying but possible. Unfortunately there are cases (when an exception is thrown) where you can't be sure that delete is properly called, and you end up with a memory leak.
The main solution is to use a smart pointer. Pre-C++11 comes with
auto_ptr
, but that cannot be used in a standard container. C++11 hasstd::unique_ptr
andstd::shared_ptr
which are designed to be usable in containers (I preferstd::unique_ptr
unless I really need reference counting). If you can't use C++11, the best solution is Boost smart pointers.