Boost logo

Boost Users :

From: JOAQUIN M. LOPEZ MUÑOZ (joaquin_at_[hidden])
Date: 2008-04-20 07:44:32


Hello Daniel

________________________________________
De: boost-users-bounces_at_[hidden] [boost-users-bounces_at_[hidden]] En nombre de damny_at_[hidden] [damny_at_[hidden]]
Enviado el: sábado, 19 de abril de 2008 17:42
Para: boost-users_at_[hidden]
Asunto: Re: [Boost-users] [multi_index] custom template class for handle multi_index map

> hi joaquin,
>
> a)
> here's a ready to use code snippet (see below).
> iisolating the problem by writing the snippet to the reuse of objects or using local
> temporary objects; i thought multi_index maps store copies of data objects, that
> where inserted. am i wrong?

As you correctly point out, multi_index_containers store copies of the data objects
you pass them, that is right. Regarding the particular piece of code where you're
getting the segfault:

  objClass01 = cClass01("elm01_01", 11);
  objClass00 = cClass00("elm00_01", 1); objClass01.setmapelm(objClass00);
  objClass00 = cClass00("elm00_02", 2); objClass01.setmapelm(objClass00);

  objClass01 = cClass01("elm01_02", 12);
  objClass00 = cClass00("elm00_03", 4); objClass01.setmapelm(objClass00);
  objClass00 = cClass00("elm00_04", 3); objClass01.setmapelm(objClass00);

  ptrClass02->setmapelm(objClass01);

  printf("START\n");
  printf( "dat = %d\n", ptrClass02->getmapelm("elm01_01")->getdat() ); // seg_vault

Please note that you've invoked ptrClass02->setmapelm only once to
insert a copy of objClass01 when this object was storing "elm01_02" as its
_nme member: no wonder that ptrClass02->getmapelm("elm01_01") returns
NULL (which is what's happening) as you haven't stored any
object with _nme=="elm01_01" inside it!! The segfault comes from trying
to dereference NULL (you invoke ->getdat() on it).

Now, if you insert two objects into ptrClass02 as follows:

  objClass01 = cClass01("elm01_01", 11);
  objClass00 = cClass00("elm00_01", 1); objClass01.setmapelm(objClass00);
  objClass00 = cClass00("elm00_02", 2); objClass01.setmapelm(objClass00);

  ptrClass02->setmapelm(objClass01); // insert objClass01

  objClass01 = cClass01("elm01_02", 12);
  objClass00 = cClass00("elm00_03", 4); objClass01.setmapelm(objClass00);
  objClass00 = cClass00("elm00_04", 3); objClass01.setmapelm(objClass00);

  ptrClass02->setmapelm(objClass01); // inserted object different than above

you won't get any segfault: ptrClass02's internal multi_index_container
will have two objects with _nme=="elm01_01" and _nme=="elm01_02",
respectively. Not sure whether this is the configuration you had in mind, though.

There is one more issue that has caught my eye: From the way you've defined
cClass01:

  class cClass01 : public ... {
  private:
    STRING _nme;
    UINT32 _dat;
  public:
           cClass01() {}
           cClass01(STRING nme, UINT32 dat)
          {
             this->_nme=nme; this->_dat=dat;
             this->_scNme = &(this->_mpMap.get<0>());
             this->_scDat = &(this->_mpMap.get<1>());
           }

you're relying on _scNme and _scDat members to point to the tCanMap
object cClass01 derives from: but you failed to guarantee this invariant
when copying or assigning cClass01's:

  cClass01 x(...);
  cClass01 y(...); // y->_scNme points to y's tCanMap base object
  x=y; // wrong!! x->_scNme points to y's tCanMap base object

Default copy ctor and assignment operator will just copy the _scNme
and _scDat pointers along, which is not what you want. You have the
same problem with cClass02. I've attached a modified version
of your code with correct copy ctors and assignment operators for
these classes.

> b)
> why it isn't possible to write (with "?" is a class attribute or template parameter; see snippet):
>
> template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2>
> const ELM *tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::getmapelm(STRING stNme) const {
> IT1 itr = this->_mpMap.get<?>().find(stNme);
> if ( itr != this->_mpMap.get<?>().end() ) { return &(*itr); }
> }

You have to insert a "template" keyword for the syntax to be correct,
for instance:

  template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2>
  const ELM *tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::getmapelm(STRING stNme) const {
    try {
      IT1 itr = this->_mpMap.template get<0>().find(stNme);
      if ( itr != this->_mpMap.template get<0>().end() ) { return &(*itr); }
    }
    catch(...) {}
    return NULL;
  }

Note the "_mpMap.template get<0>()" bit. Why "template" is needed in so-called
dependent contexts is explained at

http://www.comeaucomputing.com/techtalk/templates/#templateprefix

The attached version also includes this fix for you to experiment with. BTW, having
getmapelm() as a member of tCanMap as you tried in variants VERSION01 and
VERSION02 is a superior solution as you can dispense with _scNme and
_scDat, which pose problems of their own as commented above.

Good luck with your project,

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo




Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net