Wes Miller
Wes Miller

Reputation: 2241

C++ Accessing the members of a class which is the mapped_type in a std::map

Consider a std::map<const char *, MyClass*>.

How do I access a member (variable or function) of the MyClass object pointed to by the map?

// assume MyClass has a string var 'fred' and a method 'ethel'
std::map<const char*, MyClass*> MyMap;

MyMap[ "A" ] = new MyClass;
MyMap.find( "A" )->fred = "I'm a Mertz";  // <--- fails on compile
MyMap.find( "A" )->second->fred = "I'm a Mertz";  // <--- also fails

EDIT -- per Xeo's suggestion

I posted dummy code. Here is the real code.

// VarInfo is meta-data describing various variables, type, case, etc.
std::map<std::string,VarInfo*> g_VarMap; // this is a global 

int main( void )
{ 
   // ........ g_VarMap["systemName"] = new VarInfo; 
   g_VarMap.find( "systemName" ).second->setCase( VarInfo::MIXED, VarInfo::IGNORE ); 
   // ..... 
} 

errors were:

struct std::_Rb_tree_iterator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, VarInfo*> >’ has no member named ‘second’
Field 'second' could not be resolved Semantic Error make: *** [src/ACT_iod.o] Error 1 C/C++ Problem
Method 'setCase' could not be resolved Semantic Error – 

Upvotes: 2

Views: 6683

Answers (4)

weberc2
weberc2

Reputation: 7908

The problem is that an iterator is a pointer type, not a reference type, so iter.second will fail to compile.

Instead, you must use the pointer syntax: iter->second (arrow instead of dot).

Consider this short example:

#include <iostream>
#include <map>

int main()
{
   std::map<int, std::string> myMap;

   std::map<int, std::string>::iterator it;
   std::map<int, std::string>::iterator end = myMap.end();

   myMap.insert(std::pair<int, std::string>(0, "hello"));
   myMap.insert(std::pair<int, std::string>(1, "world"));

   for(it = myMap.begin(); it != end; ++it)
   {
      // std::cout << "Value: " << it.second << "\n";
      // The previous line will fail to compile with error:
      //    ‘struct std::_Rb_tree_iterator<std::pair<const int,
      //    std::basic_string<char, std::char_traits<char>,
      //    std::allocator<char> > > >’ has no member named ‘second’

      // The following line is correct
      std::cout << "Value: " << it->second << "\n";
   }
}

Upvotes: 1

Rontogiannis Aristofanis
Rontogiannis Aristofanis

Reputation: 9063

It fails because std::map<T, Y>::find() returns an iterator, not a reference to an MyMap object. The correct code would be:

map<const char*, MyClass*>::iterator a;
a = MyMap.find("A");
// a->fred; this is wrong too
a->second->fred = "Whatever";

Upvotes: 2

Chad
Chad

Reputation: 19032

std::map stores types internally as a std::pair, and std::map::find, returns an iterator. So, to access members of your class, you have to go through the iterator, which presents the key_type as first, and the value_type as second. Also, as others have stated, you should probably not be using const char* as your key_type. Here's a short example.

#include <string>
#include <map>
#include <iostream>

struct T
{
   T(int x, int y) : x_(x), y_(y)
   {}

   int x_, y_;
};

int main()
{
   typedef std::map<std::string, T> map_type;
   map_type m;

   m.insert(std::make_pair("0:0", T(0,0)));
   m.insert(std::make_pair("0:1", T(0,1)));
   m.insert(std::make_pair("1:1", T(1,1)));

   // find the desired item (returns an iterator to the item
   // or end() if the item doesn't exist.
   map_type::const_iterator t_0_1 = m.find("0:1");

   if(m.end() != t_0_1)
   {
      // access via the iterator (a std::pair) with 
      // key stored in first, and your contained type
      // stored in second.
      std::cout << t_0_1->second.x_ << ':' << t_0_1->second.y_ << '\n';
   }

   return 0;
}

Upvotes: 8

James Kanze
James Kanze

Reputation: 153929

The most obvious method is

MyMap[key]->fred

, but

MyMap.find( key )->second->fred

should also work. In both cases, you must ensure that the key is present before using it. In the code you've written, it (usually) won't be, since you're using the address of a specific instance of a string literal as key; a compiler is allowed to merge instances with the same value, but is not required to.

Upvotes: 1

Related Questions