Eduard Rostomyan
Eduard Rostomyan

Reputation: 6566

Why map::iterator causing compile error. C++

Please watch this:

template<typename TK, typename TV>
class MetaAssociator
{
public:

   void Set(TK key, TV const & value)
   {
      boost::lock_guard<boost::mutex> lock(m_Mutex);
      m_Map[key] = value;
   }

   TV Get(TK key) const
   {
      boost::lock_guard<boost::mutex> lock(m_Mutex);
      std::map<TK,TV>::const_iterator iter = m_Map.find(key);
      return iter == m_Map.end() ? TV() : iter->second;
   }

private:
   mutable boost::mutex m_Mutex;
   std::map<TK,TV> m_Map;
};

When I change the std::map<TK,TV>::const_iterator iter to std::map<TK,TV>::iterator it is causing the following compile error:

error C2440: 'initializing' : cannot convert from stlpd_std::priv::_DBG_iter<_Container,_Traits> to stlpd_std::priv::_DBG_iter<_Container,_Traits>

Can anyone exmplain why? I am not modifying the m_Map. Why the compiler is complaining??

Upvotes: 1

Views: 237

Answers (3)

Jerry Coffin
Jerry Coffin

Reputation: 490808

The "why" is fairly simple.

The const here:

TV Get(TK key) const
               ^^^^^

...means that this is a Mediator const *. That means you can't modify any of its contents, which is enforced through the type system by preventing you from assigning directly or obtaining a non-const reference, pointer, iterator, etc., to the content1.

The bad part is that the error message you're getting it, quite frankly terrible. I recognize it well as one MS VC++ used to generate on quite a regular basis. About the only "why" I can give here is that it simply did a poor job of reporting this type of error. About the only cure of which I'm aware is to use a different compiler. In this case, it's probably easiest to update to a newer version of MS VC++. The error messages in VC++ 2017 are much better.


  1. Though it is still possible to bypass this protection by (for example) obtaining a pointer or reference to const, then later casting away the const-ness. The compiler tries to protect you from mistakes, but if you actively bypass its protection with a cast, you're pretty much on your own.

Upvotes: 3

lisyarus
lisyarus

Reputation: 15585

Your MetaAssociator::Get method is marked as const, hence the field m_Map is also const in this method. Now, std::map::find can only return a const_iterator if the map itself is const.

This makes sense - why would you return non-const iterators to a const collection?

Upvotes: 4

Kyle
Kyle

Reputation: 4024

Your function Get is defined as const which means that access to any local properties have to be constant. ::iterator isn't constant but ::const_iterator is.

Here is something I found with a quick google search that may help you understand. https://www.studytonight.com/cpp/const-keyword.php

Just use const_iterator and you'll be fine. The compiler doesn't care if you actually modify the value, it only checks wether or not the values are constant or not.

Upvotes: 1

Related Questions