Tutorial :Help storing an intrusive_ptr of a template class in a std::map



Question:

I have a small template class of type Locker contained within a boost::intrusive_ptr that I want to store inside a std::map:

template <typename T>  bool LockerManager<T>::    AddData(const std::string& id, T* pData)  {      boost::intrusive_ptr<Locker<T> > lPtr(Locker<T>(pData)); // Line 359 - compiles      mMap.insert(make_pair(id, lPtr));  // Line 361 - gives error  }  

Locker is just a container class; its constructor looks like:

template <typename T>  Locker<T>::    Locker(T* pData)    : IntrusivePtrCountable(),      mpData(pData),      mThreadId(0),      mDataRefCount(0)  {}   

In my test of this class, I am trying to do the following:

class Clayton  {  public:    static int count;      Clayton()    { mNumber = count++;}      void GetNumber()    { cerr<<"My number is: "<<mNumber<<endl; }    private:    int mNumber;  };    int Clayton::count = 0;    class ClaytonManager  {  public:    bool AddData(const std::string& id, Clayton* pData)    { return mManager.AddData(id, pData); }    private:    LockerManager<Clayton> mManager;  };  

I get the following compile error:

Compiling LockerManagerTest.cpp                             : /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../include/c++/3.4.6/bits/stl_pair.h: In constructor `std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _U2 = boost::intrusive_ptr<Locker<Clayton> > (*)(Locker<Clayton>), _T1 = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _T2 = boost::intrusive_ptr<Locker<Clayton> >]':  ../Utilities/include/LockerManager.h:361:   instantiated from `bool LockerManager<T>::AddData(const std::string&, T*) [with T = Clayton]'  src/LockerManagerTest.cpp:35:   instantiated from here  /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../include/c++/3.4.6/bits/stl_pair.h:90: error: no matching function for call to `boost::intrusive_ptr<Locker<Clayton> >::intrusive_ptr(boost::intrusive_ptr<Locker<Clayton> > (* const&)(Locker<Clayton>))'  /usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:94: note: candidates are: boost::intrusive_ptr<T>::intrusive_ptr(const boost::intrusive_ptr<T>&) [with T = Locker<Clayton>]  /usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:70: note:                 boost::intrusive_ptr<T>::intrusive_ptr(T*, bool) [with T = Locker<Clayton>]  /usr/local/boost-1.36.0/include/boost-1_36/boost/intrusive_ptr.hpp:66: note:                 boost::intrusive_ptr<T>::intrusive_ptr() [with T = Locker<Clayton>]  Command exited with non-zero status 1  0:05.40  

Please help


Solution:1

Actually, intrusive_ptr already has a < operator and a copy constructor defined, so that wasn't the problem.

There were two main things that we were missing. First, we needed to use value_type, instead of make_pair, to avoid implicit type conversion in the insert statement. Second, we missed the fact that the intrusive_ptr constructor takes a pointer to the type that it is templated around.

So, the final, working method looks like this:

// ---------------------------------------------------------------------------  // LockerManager::AddData  // ---------------------------------------------------------------------------  template <typename T>  bool LockerManager<T>::    AddData(const std::string& id, T* pData)  {    Lock<MutualExclusion> lLock(mMutex);      if ((pData == NULL) || (mMap.find(id) != mMap.end()))      return false;      mMap.insert(typename std::map<std::string, boost::intrusive_ptr<Locker<T> > >::value_type(id, new Locker<T>(pData)));      return true;  } // LockerManager::AddData  


Solution:2

The compiler is doing its best to be helpful here. You need to define a method with the following signature:

boost::intrusive_ptr<Locker<Clayton> >::intrusive_ptr(      boost::intrusive_ptr<Locker<Clayton> > (* const&)(Locker<Clayton>)  ):  

You need to define a copy constructor for types that you store in a std::map, that's what this error message is trying to convey. You should also implement the < operator so that the following is true:

- ( x < x ) == false  - if ( x < y ), then !( y < x )  - if ( x == y ), then ( x < y ) == ( y < x ) == false  - if ( x < y ) and ( y < z ), then ( x < z )  

For many of the built-in types C++ will provide these for you, which is why some people don't know what you have to do to store custom objects in std::map and other STL containers.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »