开发者

Basic question in assigning value to unordered_map

I have an unordered_map which stores the int as key an pointer as value. I need to check the existence of the key. If the key is not available, I need to insert the key and value. Which o开发者_Python百科ne is the better approach?

Thanks.

unordered_map<int, classA*>testMap;
classA* ptr = testMap[1];
if(ptr == NULL)
   testMap[1] = new classA;


OR

unordered_map<int, classA*>::iterator it = testMap.find(1);
if(it == testMap.end())
{
  testMap.insert(make_pair(1, new classA));
}


Neither method is good because both use two queries into the map where one would be sufficient.

A better method is retrieving a reference to the element, and if that reference is a null pointer, assign to it:

classA*& ptr = testMap[1];
if (ptr == 0)
    ptr = new classA;

This works because querying a non-existing element in a map automatically inserts it (default-constructed, thus a null pointer will be inserted), and operator[] returns a reference to that element (be it newly created or already existing).

But notice that the semantics between this method (or your first method) and your second method subtly differ: your second method only inserts the element if the key doesn’t exist in the map. My method (and your first method) also create a new element if the key in fact already existed, but its value was a null pointer.


The second is the better approach. In the first, when you do classA* ptr = testMap[1], you are creating an item in the hash with the default value of NULL.

If you were to change the map value to something other than a pointer (maybe a vector for example) then you might not have a suitable default value to test against. Also, in the future, NULL might be a valid value for your map, so your default value test would be meaningless.


In terms of efficiency I believe they are equivalent.

In the first case, if the entry doesn't already exist then the call to:

classA* ptr = testMap[1];

will actually create an empty element in the map which you would then populate during the if statement.

The second will only add an entry to the map when you call insert.

So I suppose it comes down to which style suits you better!


I would do the following:

typedef unordered_map<int, classA*>::iterator my_iterator;
std::pair<my_iterator, my_iterator> range = testMap.equal_range(1);
if (range.first == range.second) //element not in map
{
    testMap.insert(range.first, new classA);
}

EDIT: Thanks to lijie for pointing out that this is pointless. equal_range returns and [end, end] pair if the value is not found for underoded_map.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜