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). i isolating 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? 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); } } thank you daniel //--- BEG ---------------------------------------------------------------------- #if defined(_Windows) || defined(_MSC_VER) || defined (__GNUC__) #define STRICT #include <windows.h> #endif #include <string> #define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING #define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE #include <boost/multi_index_container.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/mem_fun.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/hashed_index.hpp> //------------------------------------------------------------------------------ #define UINT32 unsigned long #define STRING std::string //------------------------------------------------------------------------------ // choose one //#define VERSION01 //#define VERSION02 //#define VERSION03 //#define VERSION04 //------------------------------------------------------------------------------ template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2> class tCanMap { protected: mutable MAP _mpMap; // map mutable SC1 *_scNme; // sorting criteria name ... have to init from derived class mutable SC2 *_scDat; // sorting criteria name ... have to init from derived class public: tCanMap (); MAP &getmap () const; UINT32 setmapelm (ELM val); #if defined (VERSION01) || defined (VERSION02) const ELM *getmapelm (STRING stNme) const; const ELM *getmapelm (UINT32 uiDat) const; #endif }; template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2> tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::tCanMap() { this->_scNme = NULL; this->_scDat = NULL; } template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2> MAP &tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::getmap() const { return this->_mpMap; } template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2> UINT32 tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::setmapelm(ELM val) { if (this!=NULL) { this->_mpMap.insert(val); return 0; } return 1; } #if defined (VERSION01) || defined (VERSION02) 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 { if ( this!=NULL && this->_scNme!=NULL ) { IT1 itr = this->_scNme->find(stNme); if ( itr != this->_scNme->end() ) { return &(*itr); } } } catch(...) {} return NULL; } template<typename MAP, typename ELM, typename SC1, typename IT1, typename SC2, typename IT2> const ELM *tCanMap<MAP,ELM,SC1,IT1,SC2,IT2>::getmapelm(UINT32 uiDat) const { try { if ( this!=NULL && this->_scDat!=NULL ) { IT2 itr = this->_scDat->find(uiDat); if ( itr != this->_scDat->end() ) { return &(*itr); } } } catch(...) {} return NULL; } #endif //------------------------------------------------------------------------------ class cClass00 { private: STRING _nme; UINT32 _dat; public: cClass00() {} cClass00(STRING nme, UINT32 dat) { this->_nme=nme; this->_dat=dat; } STRING getnme () const { return this->_nme; } UINT32 getdat () const { return this->_dat; } }; typedef boost::multi_index_container < cClass00, boost::multi_index::indexed_by < boost::multi_index::hashed_unique < BOOST_MULTI_INDEX_CONST_MEM_FUN(cClass00,STRING,getnme) >, boost::multi_index::ordered_unique < BOOST_MULTI_INDEX_CONST_MEM_FUN(cClass00,UINT32,getdat) >
mClass00;
typedef mClass00::nth_index<0>::type mClass00ByNme; typedef mClass00ByNme::iterator mClass00ByNmeItr; typedef mClass00::nth_index<1>::type mClass00ByDat; typedef mClass00ByDat::iterator mClass00ByDatItr; //------------------------------------------------------------------------------ class cClass01 : public tCanMap<mClass00,cClass00,mClass00ByNme,mClass00ByNmeItr,mClass00ByDat,mClass00ByDatItr> { 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>()); } STRING getnme() const { return this->_nme; } UINT32 getdat() const { return this->_dat; } #if defined (VERSION03) || defined (VERSION04) const cClass00 *getmapelm (STRING stNme) const { try { if ( this!=NULL ) { mClass00ByNmeItr itr = this->_mpMap.get<0>().find(stNme); if ( itr != this->_mpMap.get<0>().end() ) { return &(*itr); } } } catch(...) {} return NULL; } const cClass00 *getmapelm (UINT32 uiDat) const { try { if ( this!=NULL ) { mClass00ByDatItr itr = this->_mpMap.get<1>().find(uiDat); if ( itr != this->_mpMap.get<1>().end() ) { return &(*itr); } } } catch(...) {} return NULL; } #endif }; typedef boost::multi_index_container < cClass01, boost::multi_index::indexed_by < boost::multi_index::hashed_unique < BOOST_MULTI_INDEX_CONST_MEM_FUN(cClass01,STRING,getnme) >, boost::multi_index::ordered_unique < BOOST_MULTI_INDEX_CONST_MEM_FUN(cClass01,UINT32,getdat) >
mClass01;
typedef mClass01::nth_index<0>::type mClass01ByNme; typedef mClass01ByNme::iterator mClass01ByNmeItr; typedef mClass01::nth_index<1>::type mClass01ByDat; typedef mClass01ByDat::iterator mClass01ByDatItr; //------------------------------------------------------------------------------ class cClass02 : public tCanMap<mClass01,cClass01,mClass01ByNme,mClass01ByNmeItr,mClass01ByDat,mClass01ByDatItr> { public: cClass02() { this->_scNme = &(this->_mpMap.get<0>()); this->_scDat = &(this->_mpMap.get<1>()); } #if defined (VERSION03) || defined (VERSION04) const cClass01 *getmapelm (STRING stNme) const { try { if ( this!=NULL ) { mClass01ByNmeItr itr = this->_mpMap.get<0>().find(stNme); if ( itr != this->_mpMap.get<0>().end() ) { return &(*itr); } } } catch(...) {} return NULL; } const cClass01 *getmapelm (UINT32 uiDat) const { try { if ( this!=NULL ) { mClass01ByDatItr itr = this->_mpMap.get<1>().find(uiDat); if ( itr != this->_mpMap.get<1>().end() ) { return &(*itr); } } } catch(...) {} return NULL; } #endif }; //------------------------------------------------------------------------------ int main(void) { #if defined (VERSION01) || defined (VERSION03) // works fine in any case cClass00 objClass00_01 = cClass00( "elm00_01", 1 ); cClass00 objClass00_02 = cClass00( "elm00_02", 2 ); cClass00 objClass00_03 = cClass00( "elm00_03", 3 ); cClass00 objClass00_04 = cClass00( "elm00_04", 4 ); cClass01 objClass01_01 = cClass01( "elm01_01", 11 ); cClass01 objClass01_02 = cClass01( "elm01_02", 12 ); objClass01_01.setmapelm( objClass00_01 ); objClass01_01.setmapelm( objClass00_02 ); objClass01_02.setmapelm( objClass00_03 ); objClass01_02.setmapelm( objClass00_04 ); cClass02 *ptrClass02_01 = new cClass02(); ptrClass02_01->setmapelm( objClass01_01 ); ptrClass02_01->setmapelm( objClass01_02 ); printf("START\n"); printf("\n"); printf( "1. try: %02d\n", ptrClass02_01->getmapelm("elm01_01")->getdat() ); printf( "2. try: %02d\n", ptrClass02_01->getmapelm("elm01_02")->getdat() ); printf("\n"); printf( "3. try: %02d\n", ptrClass02_01->getmapelm("elm01_01")->getmapelm("elm00_01")->getdat() ); printf( "4. try: %02d\n", ptrClass02_01->getmapelm("elm01_02")->getmapelm("elm00_04")->getdat() ); printf("\n"); printf( "5. try: %s\n", ptrClass02_01->getmapelm("elm01_01")->getmapelm(2)->getnme().c_str() ); printf( "6. try: %s\n", ptrClass02_01->getmapelm("elm01_02")->getmapelm(3)->getnme().c_str() ); printf("\n"); printf("DONE\n"); #elif defined (VERSION02) || defined (VERSION04) // run into segvault if object become overwritten OR // object for filling multi_index is only a local variable of a filling function cClass02 *ptrClass02 = new cClass02(); cClass01 objClass01; cClass00 objClass00; 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 // printf( "dat = %d\n", ptrClass02->getmapelm("elm01_02")->getdat() ); // works fine printf("DONE\n"); #endif } //--- END ---------------------------------------------------------------------- ______________________________________________________ Bis 50 MB Dateianhänge? Kein Problem! http://freemail.web.de/club/landingpage.htm/?mc=025556
Hello Daniel ________________________________________ De: boost-users-bounces@lists.boost.org [boost-users-bounces@lists.boost.org] En nombre de damny@web.de [damny@web.de] Enviado el: sábado, 19 de abril de 2008 17:42 Para: boost-users@lists.boost.org 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
participants (2)
-
damny@web.de
-
JOAQUIN M. LOPEZ MUÑOZ