tags:

views:

166

answers:

1

I'm trying to use a Boost MultiIndex container in my simulation. My knowledge of C++ syntax is very weak, and I'm concerned I'm not properly removing an element from the container or deleting it from memory. I also need to modify elements, and I was hoping to confirm the syntax and basic philosophy here too.

// main.cpp
...
#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>
#include <boost/shared_ptr.hpp>
...
#include "Host.h" // class Host, all members private, using get fxns to access

using boost::multi_index_container;
using namespace boost::multi_index;

typedef multi_index_container<
  boost::shared_ptr< Host >,
  indexed_by< 
    hashed_unique< const_mem_fun<Host,int,&Host::getID> >
    //   ordered_non_unique< BOOST_MULTI_INDEX_MEM_FUN(Host,int,&Host::getAge) >
    > // end indexed_by
  > HostContainer;

typedef HostContainer::nth_index<0>::type HostsByID;

int main() {
   ...
   HostContainer allHosts;
   Host * newHostPtr;
   newHostPtr = new Host( t, DOB, idCtr, 0, currentEvents );
   allHosts.insert( boost::shared_ptr<Host>(newHostPtr) );
   // allHosts gets filled up

   int randomHostID = 4;
   int newAge = 50;
   modifyHost( randomHostID, allHosts, newAge );
   killHost( randomHostID, allHosts );
}

void killHost( int id, HostContainer & hmap ){
  HostsByID::iterator it = hmap.find( id );
  cout << "Found host id " << (*it)->getID() << "Attempting to kill. hmap.size() before is " << hmap.size() << " and ";
  hmap.erase( it ); // Is this really erasing (freeing from mem) the underlying Host object?
  cout << hmap.size() << " after." << endl;
}

void modifyHost( int id, HostContainer & hmap, int newAge ){
  HostsByID::iterator it = hmap.find( id );
  (*it) -> setAge( newAge ); // Not actually the "modify" function for MultiIndex...
}

My questions are

  1. In the MultiIndex container allHosts of shared_ptrs to Host objects, is calling allHosts.erase( it ) on an iterator to the object's shared_ptr enough to delete the object permanently and free it from memory? It appears to be removing the shared_ptr from the container.
  2. The allhosts container currently has one functioning index that relies on the host's ID. If I introduce an ordered second index that calls on a member function (Host::getAge()), where the age changes over the course of the simulation, is the index always going to be updated when I refer to it?
  3. What is the difference between using the MultiIndex's modify to modify the age of the underlying object versus the approach I show above?
  4. I'm vaguely confused about what is assumed/required to be constant in MultiIndex.

Thanks in advance.


Update

Here's my attempt to get the modify syntax working, based on what I see in a related Boost example.

struct update_age {
  update_age():(){} // have no idea what this really does... elicits error
  void operator() (boost::shared_ptr<Host> ptr) {
    ptr->incrementAge(); // incrementAge() is a member function of class Host
  }
};

and then in modifyHost, I'd have hmap.modify(it,update_age). Even if by some miracle this turns out to be right, I'd love some kind of explanation of what's going on.

+1  A: 

shared_ptr will remove actual Host object in its destructor (if there is no other instances of shared_ptr). All objects in MultiIndex are considered constant. To modify the object you should use method modify of MultiIndex. In that case indexes will be updates if necessary.

You could use the following functor to change age field:

  struct change_age
  {
    change_age(int age) : age_(age) {}    
    void operator()(boost::shared_ptr<Host> h) // shared_ptr !!!
    {
      h->age = age_;
    }

  private:
    int age_;
  };

Then use it as follows:

  testHosts.modify( it, Host::change_age( 22 ) ); // set age to 22
Kirill V. Lyadvinsky
Thanks again. Even after studying your link, I'm still having trouble with the modify syntax. Using hmap.modify(it,incrementAge()), with Host::incrementAge(), causes an out-of-scope error. I see some examples using structs (when the container elements are the objects themselves) but can't follow why my code doesn't work.
Sarah
Updated my answer to show how to use `modify`.
Kirill V. Lyadvinsky
Thanks, Kirill--that's very useful. (I have other member functions that take inputs, and that I will need to invoke with modify().) I'm still confused about what to do when I'm just trying to call a member function that doesn't take inputs, though--is my edited code above right?
Sarah
You should pass functor object to a `modify` function. In your case it will look like `hmap.modify( it, update_age() )`.
Kirill V. Lyadvinsky
The struct I proposed above yields the following compiler errors: "main.cpp:76: error: anachronistic old-style base class initializermain.cpp:76: error: unnamed initializer for ‘update_age’, which has no base classes"
Sarah
I commented out the stupid line (update_age():(){} ), and everything looks like it's working!
Sarah