I am working in cross platform C++, and have some classes defined like so: (heavily simplified for this example)
class ExampleBase
{
public:
ExampleBase( int blah ) : blah_test(blah) { }
virtual void DoSomething( ) = 0;
private:
int blah_test;
};
class ExampleImplementer : public ExampleBase
{
public:
ExampleImplementer( ) : ExampleBase( 5 ) { }
virtual void DoSomething( ) { /* unique implementation here */ }
};
Originally I had only a single class, which I stored a bunch of instances of in a std::vector and passed around by const reference. But now I need to have a base class (that I want to keep pure virtual) and a number of polymorphic implementing classes.
What is the best way to have a collection of any implementing instances, and still have leak free easy memory management like having a stack allocated std::vector?
Obviously I can't have a std::vector< ExampleBase > now, since std::vector requires the class to be non-pure virtual (since it does internal allocation/copying etc.). I don't want users of my code to accidentally create instances of ExampleBase because that is wrong. I also want to steer clear from any possibilities of object slicing or any other nasties.
An array of std::auto_ptr
would do the job, but then I have to deal with initializing them all, looking for a "free slot", no iterators etc. It seems a bit crazy to do all of this wheel re-inventing.
boost::ptr_vector
looked promising, however it behaves a little weirdly in that when building on Linux it needs ExampleBase to be non-pure virtual - and I don't understand why... So boost::ptr_vector
is out.
This seems to be a simple, and probably really common situation. So what is the best way to do this? I am open to any other std or boost way of doing this: whichever is "best".
boost::ptr_vector
is the way to go if you can have Boost. It should work for your scenario - if it does not, then something else is wrong, so please post the error message.
Alternatively, you can go for std::vector< boost::shared_ptr<ExampleBase> >
. This is less ideal, because that refcounting will add some overhead, especially when vector is resized, but otherwise a working solution.
If your implementation supports TR1 (latest versions of g++ and MSVC), then you can use std::tr1::shared_ptr
instead. This can actually be superior, because STL implementation is free to optimize based on some inner knowledge - for example, in MSVC, std::vector
knows that it can use swap
instead of copy constructor for std::tr1::shared_ptr
, and does just that, avoiding constant refcount changes.