maps

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?
Give A a constructor that doesn't take any parameters, such as A::A(){}
Wow. Totally worked. Why is it that my defined class must have a parameter-less constructor in order to use []?
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.

@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



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.
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.
Ah, thanks! That makes sense.
@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
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.