简体   繁体   中英

Safe to use += operator to create a new std::map entry using []?

Let's say I have a std::map<int, int> , would it be safe to do this?

std::map<int, int> m_map;
m_map[0] += 1;

If the key 0 didn't exist in the map when I do this, how would it know what value to add 1 to?

What I'm hoping is that std::map handles this by performing an = instead of += in the case where the value creates a new entry in the map. This would spare me from having to do:

std::map<int, int>::iterator it = m_map.find(0);
if(it != m_map.end()) {
    it->second += 1;
}
else {
    m_map[0] = 1;
}

An element inserted into a map on invoke of operator[] due to a previously-unmapped key is value-initialized . If you've not seen that syntax, consider the special meaning the () has in the following code snippet. The parens are important. They introduce an different trip down the initialization tree than default-initialization . Both are important; both are laid out by the language standard.

int i = int();

As it turns out, value initialization for scalars (including pointers) eventually succumbs to zero-initialization . Though odd looking, the prior snippet value-initializes an instance of int , which becomes zero-initialization since int is a scalar, then copies it to i . (To be fair, there will almost certainly be some eliding, but the fundamentals are as-presented).

Regardless, due to that feature, you can rest assured when you do this:

m_map[0] += 1;

or even this:

++m_map[0];

if the index wasn't mapped prior, a value-initialized element is added, which will zero-initialize for scalars, which means you'll officially starting out with zero .

It is worth mentioning that a similar activity happens for any type with an implicitly declared constructor. Whether trivial or not, something interesting happens.

struct S { int a; int b; };
std::map<int, S> mymap;

++mymap[0].a;

Is the a member mapped to 0 in our container reliably 1 after the above executes? Yes , it is. Further, consider this:

struct S { int a; std::string str; };
std::map<int, S> mymap;

++mymap[0].a;

Now S has a non-trivial implicit constructor (it has to, as it must construct str ). But is the a member mapped to 0 in our container still reliably zero-initialized (and therefore 1 after the above line)? Yes , it is.

If curious about the referenced different paths of initialization, see this question and answer . Or review the C++11 standard, particularly C++11 § 8.5 Initializers, (p5,p7,p10) . It is worth the read.

It's guaranteed that you'll get 1 even with the shorter snippet.

The key is that operator[] has to create the element in the map before returning a reference to it, so by the time you got to += the element already exists, and, if it had to be created now, with value zero (since elements of a map are value-initialized).

(incidentally, this is the reason why, when you use an std::map with a class type as value, it has to have a default constructor if you want to use operator[] , even if you assign an object to it immediately)

Yes this is fine, new entries default to value value_type() which is 0 for int .

It still does += , but 0 += 1 gives 1 .

Map is lazily initialize with default constructor.(zero for all int)

So it 0 didn't exist in map, it would be initialized to contain value 0 and 1 would be added after += 1 .

So you can use upper version of code without any worries.

Quoting Effect of calling map_obj[k] from cplusplus.com

If k matches the key of an element in the container, the function returns a reference to its mapped value.

If k does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the container size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM