tags:

views:

148

answers:

1

I'm programming an agent-based simulation and have decided that Boost's MultiIndex is probably the most efficient container for my agents. I'm not a professional programmer, and my background is very spotty. I've two questions:

  1. Is it better to have the container contain the agents (of class Host) themselves, or is it more efficient for the container to hold Host *? Hosts will sometimes be deleted from memory (that's my plan, anyway... need to read up on new and delete). Hosts' private variables will get updated occasionally, which I hope to do through the modify function in MultiIndex. There will be no other copies of Hosts in the simulation, i.e., they will not be used in any other containers.
  2. If I use pointers to Hosts, how do I set up the key extraction properly? My code below doesn't compile.
// main.cpp - ATTEMPTED POINTER VERSION
...
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/tokenizer.hpp>

typedef multi_index_container<
  Host *,
  indexed_by< 
    // hash by Host::id
    hashed_unique< BOOST_MULTI_INDEX_MEM_FUN(Host,int,Host::getID) > // arg errors here
    > // end indexed_by
  > HostContainer;

...
int main() {

   ...
   HostContainer testHosts;
   Host * newHostPtr;
   newHostPtr = new Host( t, DOB, idCtr, 0, currentEvents );
   testHosts.insert( newHostPtr );
   ... 
}

I can't find a precisely analogous example in the Boost documentation, and my knowledge of C++ syntax is still very weak. The code does appear to work when I replace all the pointer references with the class objects themselves.


As best I can read it, the Boost documentation (see summary table at bottom) implies I should be able to use member functions with pointer elements.

+2  A: 

If Host contains lot of data you could use shared_ptr to avoid copying. You could use MultiIndex with shared_ptr in it:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost::multi_index;

struct Host
{
   int get_id() const { return id; }
 private:
   int id;
   // more members here
};

typedef multi_index_container<
  boost::shared_ptr<Host>,    // use pointer instead of real Host
  indexed_by< 
    // hash using function Host::get_id
    hashed_unique< const_mem_fun<Host, int, &Host::get_id> >
    > // end indexed_by
  > HostContainer;

Then you could use it as follows:

int main()
{
   HostContainer testHosts;
   Host * newHostPtr;
   newHostPtr = new Host;
   testHosts.insert( boost::shared_ptr<Host>(newHostPtr) );

  return 0;
}
Kirill V. Lyadvinsky
Thank you for the help. I'll look into shared pointers--if I don't use a ptr, does that mean that each object is stored in two places in memory (once upon creation and then again in the container)? Also, Host is a class, and Host::id is a private member variable. I'm trying to figure out how to use the member function Host::getID() as my key extractor if HostContainer is full of Host * or shared_ptr<Host>...
Sarah
Added member function `get_id` to my answer. If you do not use `shared_ptr` it means that every `Host` will be copied into MultiIndex container and copy will be there until you remove it from there.
Kirill V. Lyadvinsky
Sarah
How your `getID` was defined? My sample compiles without errors.
Kirill V. Lyadvinsky
In 'Host.cpp,' it's const int Host::getID( void ) { return id;}
Sarah
Your function is not `const`. You should define it as `int Host::getID( void ) const { return id; }` since elements in a multi_index_container are treated as constant.
Kirill V. Lyadvinsky
Now it compiles! Thank you! I tried to read off the ids with an iterator, starting at HostContainer::iterator it = testHosts.begin() and asking for it->getID(), and I'm getting ‘const class boost::shared_ptr<Host>’ has no member named ‘getID’. My syntax seems to agree with the examples I can find... many thanks again.
Sarah
To get id from iterator you could write `(*it)->getID()` or `it->get()->getID()`.
Kirill V. Lyadvinsky
Woooooo! Thank you! I had been thinking get() was extraneous. Will study Boost ptrs in more detail.
Sarah