Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does setting an element of a map to its size increments the size *before* assigning it?

This is a common pattern I use to index tokens as they come in: check if the token is in a map, and if not, add it to the map, assigning the map's size.

When doing this in C++, it unexpectedly increments the map's size before the assignment is made:

#include <cstdio>
#include <map>
using namespace std;

int main() {
    map<char, int> m;
    printf("Size before adding: %d\n", m.size());
    m['A'] = m.size();
    printf("Size after adding: %d\n", m.size());
    printf("What was added: %d\n", m['A']);

    return 0;
}

This prints out:

Size before adding: 0
Size after adding: 1
What was added: 1

The way I understand it, it should evaluate the right hand side, which is zero, then pass it to a function that puts 'A' and the zero into the map. But it seems to be evaluating it after it started assigning, which doesn't make sense.

Shouldn't the right-hand side be evaluated before the assignment operation?

like image 937
Evgeni Sergeev Avatar asked Aug 04 '13 05:08

Evgeni Sergeev


2 Answers

The behavior is unspecified, pedantically speaking.

But what happens in your case is this:

m['A'] = m.size();

m is a std::map which creates a new entry if the key doesn't exist.

In your case, the key 'A' doesn't exist, so it creates the entry, and return the reference to the value (which is default created) which then is assigned to m.size() in your case.

As said above, the behaviour is unspecified, as the order of evaluation of operands is unspecified which means m.size() might be evaluated before m['A']. If it does, then m['A'] will be 0, not 1.

like image 92
Nawaz Avatar answered Nov 15 '22 16:11

Nawaz


No.

(§5.17/1): "In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression."

Note, however, that while the assignment happens after the right and left operands are evaluated, no sequencing is specified between the evaluation of the left and right operands themselves. Therefore, the left could be evaluated first, then the right, or vice versa.

like image 24
Jerry Coffin Avatar answered Nov 15 '22 17:11

Jerry Coffin