maps

Mar 9, 2009 at 6:53pm
Hi, I'm trying to use a map with a string key to store a user defined class and seem to be running into problems. I'm using g++ and am getting a big barf of errors:

1
2
3
4
5
6
7
8
9
10
11
/usr/include/c++/4.0.0/bits/stl_map.h: In member function ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = std::string, _Tp = A, _Compare = std::less, _Alloc = std::allocator >]’:

main.cpp:50: instantiated from here

/usr/include/c++/4.0.0/bits/stl_map.h:339: error: no matching function for call to ‘A::A()’

main.cpp:17: note: candidates are: A::A(std::string)

main.cpp:15: note: A::A(const A&)

make: *** [main.o] Error 1


Here is my code so far:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <map>
#include <string>

using namespace std;

class A
{
public:
	A(string k)
	{
		key = k;
	}
	void print()
	{
		printf("This is A.print(), key=>%s\n", key.c_str());
	}
	string key;
};

//--------------------------------------
//  MAIN
//--------------------------------------

int main(int argc, char** argv)
{
	map<string, A> mymap;
	string s = "string";
	A a ("keystring");
	
	mymap.insert(pair<string, A>(s, a));

	A b = mymap[s];   // if i comment this out, everything is fine.

	cout << "mymap now contains " << (int) mymap.size() << " elements." << endl;
	
	return 0;
}


If I comment out the "A b = mymap[s];" line, everything is fine, but if I try any code that uses the [] operator I get the same general compiler error. I'm sure this is just some gotcha I have to get through, can anyone help?
Mar 9, 2009 at 7:17pm
Give A a constructor that doesn't take any parameters, such as A::A(){}
Mar 9, 2009 at 9:45pm
Wow. Totally worked. Why is it that my defined class must have a parameter-less constructor in order to use []?
Mar 9, 2009 at 10:11pm
because operator[] has the side effect of creating a new key-value pair if the key being sought after does not exist. because there is no value specified for the given key, it has to default construct the value.

Mar 9, 2009 at 10:16pm
@helios: While it is working, but what I don't understand is, why is A b = mymap[s] ; not calling the copy constructor?
As map's value is of type A and technically, mymap[s] should return A. Right?

Could you please explain it a little bit?

Thanks



Mar 9, 2009 at 10:40pm
map's operator[] has to be implemented something like this:

1
2
3
4
5
6
// horrible and wrong implementation, but to demonstrate the point:
value_type operator[]( const key_type& key ) {
   if( find( key ) == end() )
       insert( make_pair( key, value_type() ) );
   return find( key )->second;
}


The insert line has to compile even if it doesn't execute. It will only compile if value_type is default constructible.
Mar 9, 2009 at 10:43pm
That line doesn't call the copy constructor. It first constructs b without parameters and then calls A::operator=(). If A::operator=() is not defined, the compiler defines one of its own that shallow-copies the right-hand operand into the left-hand operand.
Mar 9, 2009 at 11:10pm
Ah, thanks! That makes sense.
Mar 9, 2009 at 11:22pm
@helios: I am sorry if I sound stupid, but I think I did not understood what you said: As if I am not wrong then, since A b = mymap[s]; at this point b has been declared right. So consider this code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<iostream>
using namespace std;


class A { 

public:
 A() { cout<<"Constructor"<<endl; 
 } 
 A(A& o) {
    cout<<"Copy Constructor"<<endl; 
 }
};  

int main() { 

A a;  
A b = a;   // This will call copy constructor 

return 0;

 };


A b = a; will be valid because I have not specified "explicit keyword" in front of my copy constructor. So in the above code, line A b = a; will call copy constructor and not default constructor. And I see the similar relationship in the code mentioned in the first post. Could you please point where I am going wrong ?

Thanks
Mar 9, 2009 at 11:51pm
You are right; it is likely that A b = mymap[s]; will call the copy constructor to copy the return value from operator[] to b.

copy constructors cannot be declared explicit (or at least it would be silly to do so).

Topic archived. No new replies allowed.