Saying we have std::unordered_multiset
with two values mapping the same hash value, is there any guarantees by the c++ standard that a find will return the first inserted element ?

- 10,303
- 14
- 70
- 145
2 Answers
Interesting question. Haven't used unordered associative containers a lot, so I took the chance to search the standard. Here is my interpretation: 23.2.5.6 says
"In containers that support equivalent keys, elements with equivalent keys are adjacent to each other in the iteration order of the container. Thus, although the absolute order of elements in an unordered container is not specified, its elements are grouped into equivalent-key groups such that all elements of each group have equivalent keys."
But then continues with
"Mutating operations on unordered containers shall preserve the relative order of elements within each equivalent-key group unless otherwise specified."
23.2.5.9 then states
"For unordered_multiset and unordered_multimap, rehashing preserves the relative ordering of equivalent elements."
So the order seems to be preserved, because insert does not say that it may change the order of equivalent keys. But then, find is specified as
"Returns an iterator pointing to an element with key equivalent to k, or b.end() if no such element exists."
So, it does not defined which element of the equivalent keys ones it returns. Strictly, this may return a random element with given key and still fulfill the specification. Given that equal_range is defined as
Returns a range containing all elements with keys equivalent to k.
*equal_range(k).first
could do the job and return the first element inserted with key k.

- 9,058
- 2
- 26
- 43
-
I appreciate the suggestion to use equal_range. – Darryl Mar 14 '14 at 21:42
I'm assuming your question is about two keys that not only generate the same hash value, but also compare equal using the equality predicate supplied to the unordered_multiset
. unordered_multiset::find
will only use the hash value to initially locate the bucket within which to search, but after that the search is done using the equality predicate.
§23.2.5 [unord.req] Table 103 — Unordered associative container requirements
b.find(k)
Returns an iterator pointing to an element with key equivalent to
k
, orb.end()
if no such element exists.
No additional requirements for find()
are placed upon the unordered_multi*
containers. This means implementations are not required that unordered_multiset::find
return an iterator to the first inserted element. But then again, if the two (or more) keys are truly equivalent, why would you care?

- 106,671
- 19
- 240
- 328
-
I care about that because the fields using to compute the equality are equal but some others fields may not be equal, like a datetime field. Maybe I can override the operator < to have a control on the way elements will be inserted inside a particular bucket ? – Guillaume Paris Mar 16 '14 at 09:29
-
1@Guillaume07 Overloading `operator<` will not give you any such guarantee, your best bet is to use `unordered_multiset::equal_range` and iterate over the returned range. Maybe set a data member in the item you're about to insert indicating the insertion order. What I was trying to convey with the final sentence in my answer was that it sounds like you should avoid this problem by not having the elements compare equal in the first place. Why not use all fields to determine equality? Maybe you should explain what problem you're trying to solve as well, there may be an alternate solution. – Praetorian Mar 16 '14 at 23:11
-
I need to match two elements which have a field with a different value , I will use `unordered_multiset::equal_range`. – Guillaume Paris Mar 17 '14 at 11:48