tags:

views:

166

answers:

4

I was going through Josuttis's "Using Map's as associative arrays" and came across Using a std::map as an associative array in this forum. Now I have more questions on the constructors that are called when inserting into map.

Here is my sample program, ( Not using best coding practices, 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 intialization better?

Thanks.

A: 

What happens if you simply execute map[1];? This may involve internal copies, depending on the implementation of map your standard library uses.

coppro
+2  A: 

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)
Martin York
+7  A: 

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.

Andrey
Nice and succinct.
jon hanson
Same as my answer, only better! +1 and deleted mine.
Éric Malenfant
Nice response, re-read the spec and it did make lot of sense now.
mithuna
Matthieu M.
A: 

Actually map1[1] = obj will create pair first

BostonLogan