c++interfacecontainersheterogeneous

What would be the safest way to store objects of classes derived from a common interface in a common container?


I'd like to manage a bunch of objects of classes derived from a shared interface class in a common container.

To illustrate the problem, let's say I'm building a game which will contain different actors. Let's call the interface IActor and derive Enemy and Civilian from it.

Now, the idea is to have my game main loop be able to do this:

// somewhere during init
std::vector<IActor> ActorList;
Enemy EvilGuy; 
Civilian CoolGuy;
ActorList.push_back(EvilGuy);
ActorList.push_back(CoolGuy);

and

// main loop
while(!done) {
    BOOST_FOREACH(IActor CurrentActor, ActorList) {
        CurrentActor.Update();
        CurrentActor.Draw();
    }
}

... or something along those lines. This example obviously won't work but that is pretty much the reason I'm asking here.

I'd like to know: What would be the best, safest, highest-level way to manage those objects in a common heterogeneous container? I know about a variety of approaches (Boost::Any, void*, handler class with boost::shared_ptr, Boost.Pointer Container, dynamic_cast) but I can't decide which would be the way to go here.

Also I'd like to emphasize that I want to stay away as far as possible from manual memory management or nested pointers.

Help much appreciated :).


Solution

  • As you have guessed you need to store the objects as pointers.
    I prefer to use the boost pointer containers (rather than a normal container of smart pointers).

    The reason for this is the boost ptr container access the objects as if they were objects (returning references) rather than pointers. This makes it easier to use standard functors and algorithms on the containers.

    The disadvantage of smart pointers is that you are sharing ownership.
    This is not what you really want. You want ownership to be in a single place (in this case the container).

    boost::ptr_vector<IActor> ActorList; 
    ActorList.push_back(new Enemy()); 
    ActorList.push_back(new Civilian());
    

    and

    std::for_each(ActorList.begin(), 
                  ActorList.end(),
                  std::mem_fun_ref(&IActor::updateDraw));