|
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