Reputation: 1101
I was going through Josuttis's "Using Map's as associative arrays" (from The C++ Standard Library - A Tutorial and Reference, 2nd Edition) and came across Using a std::map as an associative array on Stack Overflow. Now I have more questions on the constructors that are called when inserting into a map.
Here is my sample program (not using best coding practices; please excuse me for that):
class C
{
public:
string s;
C() { cout << "default " << endl;}
C(const string& p) : s(p)
{ cout << "one param" << endl;}
C(const C& obj)
{
if (this != &obj)
{
s = obj.s;
}
cout << "copy constr" << endl;
}
C& operator = (const C& obj)
{
if (this != &obj)
{
s = obj.s;
}
cout << "copy initializer" << endl;
return *this;
}
};
int main()
{
map<int,C> map1;
C obj("test");
cout << "Inserting using index" << endl;
map1[1] = obj;
cout << "Inserting using insert / pair" << endl;
map1.insert(make_pair(2,obj));
}
The output for this program is:
one param
Inserting using index
default
copy constr
copy constr
copy initializer
Inserting using insert / pair
copy constr
copy constr
copy constr
copy constr
I was assuming that initializing the map by index should call the default constructor and followed by the assignment operator.
But executing map1[1] = obj
creates following output;
Inserting using index
default
copy constr
copy constr
copy initializer
Can someone help me to understand the initialization better?
Upvotes: 7
Views: 604
Reputation: 858
If you read the specification for std::map, it says that operator[] is equivalent to (in this case)
(*((this->insert(make_pair(1,C()))).first)).second
So this explains all the constructor calls you see. First it calls the default constructor C(). Then it calls make_pair, which copies the C object. Then it calls insert, which makes a copy of the pair object you just made, calling the C copy constructor again. Finally it calls the assignment operator to set the inserted object to the one you are assigning it to.
Upvotes: 9
Reputation: 264331
Don;t know. But this is interesting:
#include <string>
#include <map>
#include <iostream>
using namespace std;
class C
{
public:
string s;
C()
{
cout << "default " << endl;
}
C(const string& p)
: s(p)
{
cout << "one param(" << s << ")" << endl;
}
C(const C& obj)
:s(obj.s)
{
cout << "copy constr(" << s << ")" <<endl;
}
C& operator = (const C& obj)
{
cout << "copy initializer\t" <<;
C copy(obj);
std::swap(s,copy.s);
return *this;
}
};
int main()
{
map<int,C> map1;
cout << "Inserting using index" << endl;
map1[1] = C("Plop");
}
It looks like the default one is created and copied around.
Then the external one is just assinged over it once it has been put in place.
Inserting using index
default
copy constr()
copy constr()
one param(Plop)
copy initializer copy constr(Plop)
Upvotes: 2
Reputation: 14506
What happens if you simply execute map[1];
? This may involve internal copies, depending on the implementation of map
your standard library uses.
Upvotes: 0