mithuna
mithuna

Reputation: 1101

Need help understanding using C++ map as an associative array

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

Answers (4)

BostonLogan
BostonLogan

Reputation: 1596

Actually map1[1] = obj will create pair first

Upvotes: 0

Andrey
Andrey

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

Loki Astari
Loki Astari

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

coppro
coppro

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

Related Questions