rahman
rahman

Reputation: 4948

initialize std::map value when its key does not exist

I read in here that the std::map operator[] create an object if the key doesn't exist !

1st of all may I know where I can find a reference for this claim?(Although I know it is true)

Next, imagin the following code snippet:

#include <iostream>
#include <vector>
#include<map>

class Value {
//..
    int some_member; //is used for any purpose that you like
    std::vector<int> some_container;
public:
    Value(int some_member_) :
            some_member(some_member_) {
        std::cout << "Hello from the one-argument constructor" << std::endl;
    }
    Value() {
        std::cout << "Hello from the no argument constructor" << std::endl;
    }
    void add(int v) {
        some_container.push_back(v);
    }
    int getContainerSize()
    {
        return some_container.size();
    }

//...
};

//and somewhere in the code:

class A {
public:
    std::map<int, Value> myMap;

    void some_other_add(int j, int k) {
        myMap[j].add(k);
    }
    int getsize(int j)
    {
        return myMap[j].getContainerSize();
    }

};
//and the program actually works
int main() {
    A a;
    std::cout << "Size of container in key 2 = " << a.getsize(2) << std::endl;
    a.some_other_add(2, 300);
    std::cout << "New Size of container in key 2 = " << a.getsize(2) << std::endl;

    return 1;
}

output:

Hello from the no argument constructor
Size of container in key 2 = 0
New Size of container in key 2 = 1

I can see from the above output that the no-argument constructor is invoked.

My question is: Is there any way to invoke the one-argument constructor of map's Value(s) ?

thank you

Upvotes: 4

Views: 5366

Answers (2)

Marcelo Cantos
Marcelo Cantos

Reputation: 185852

You'll find a helpful description of std::map<…>::operator[] at cppreference.com.

I assume you want to conditionally add a Value using a non-default constructor, i.e., when the corresponding key isn't present in the map.

C++03

std::map<int, Value>::iterator i = myMap.find(j);
if (i == myMap.end())
    i = myMap.insert(std::map<int, Value>::value_type(j, 123)).first;
i->add(k);

C++11

auto i = myMap.find(j);
if (i == myMap.end())
    i = myMap.emplace(j, 123).first;
i->add(k);

In both cases, newly inserted Values will have some_member == 123.

Upvotes: 4

Andy Prowl
Andy Prowl

Reputation: 126412

may I know where I can find a reference for this claim?

This is what the C++11 Standard mandates. Per paragraph 23.4.4.3:

T& operator[](const key_type& x);

1 Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.

[...]

T& operator[](key_type&& x);

5 Effects: If there is no key equivalent to x in the map, inserts value_type(std::move(x), T()) into the map.

Concerning the second question:

Is there any way to invoke the one-argument constructor of map's Value(s) ?

You could do this in C++03:

void some_other_add(int j, int k) {
    myMap.insert(std::make_pair(j, Value(k)));
}

And use the emplace() member function in C++11:

myMap.emplace(j, k);

Upvotes: 7

Related Questions