tags:

views:

79

answers:

1

I need some help understanding how stdext::hash_multimap's lower_bound, upper_bound and equal_range work (at least the VS2005 version of it).

I have the following code (summarized for the question)

#include <hash_map>

using stdext::hash_multimap;
using std::greater;
using stdext::hash_compare;
using std::pair;
using std::cout;

typedef hash_multimap < double, CComBSTR, hash_compare< double, greater<double> > > HMM;
HMM hm1;
HMM :: const_iterator it1, it2;
pair<HMM::const_iterator, HMM::const_iterator> pairHMM;

typedef pair <double, CComBSTR> PairDblStr;

// inserting only two values for sample
hm1.insert ( PairDblStr ( 0.224015748, L"#1-64" ) );
hm1.insert ( PairDblStr ( 0.215354331, L"#1-72" ) );

// Using a double value in between the inserted key values to find one of the elements in the map
it1 = hm1.lower_bound( 0.2175 );

if( it1 == hm1.end() )
{
    cout << "lower_bound failed\n";
}

it1 = hm1.upper_bound( 0.2175 );

if( it1 == hm1.end() )
{
    cout << "upper_bound failed\n";
}

pairHMM = hm1.equal_range( 0.2175 );
if( ( pairHMM.first == hm1.end() ) && ( pairHMM.second == hm1.end() ) )
{
    cout << "equal_range failed\n";
}

As mentioned in the comment I am passing in a value (0.2175) that is in between the two inserted key values (0.224015748, 0.215354331). But the output of the code is:

lower_bound failed
upper_bound failed
equal_range failed

Did I misunderstand how the lower_bound, upper_bound and equal_range can be used in maps? Can we not find a "closest match" key using these methods? If these methods are not suitable, would you have any suggestion on what I could use for my requirement?

Thanks in advance for any help.

Thanks to @billy-oneal @dauphic for their comments and edits. I have updated the code above to make it compilable and runnable (once you include the correct headers of course).

+2  A: 

Can we not find a "closest match" key using these methods?

No. hash_multimap is implemented using a hashtable. Two keys that are very close to each other (0.2153 and 0.2175, for example) will likely map to totally different bins in the hashtable.

A hashtable does not maintain its elements in a sorted order, so you cannot find the closest match to a given key without a linear search.

The lower_bound, upper_bound, and equal_range functions in hash_multimap have a somewhat odd implementation in the Visual C++ standard library extensions.

Consider the documentation for lower_bound:

The member function determines the first element X in the controlled sequence that hashes to the same bucket as key and has equivalent ordering to key. If no such element exists, it returns hash_map::end; otherwise it returns an iterator that designates X. You use it to locate the beginning of a sequence of elements currently in the controlled sequence that match a specified key.

And the documentation for upper_bound:

The member function determines the last element X in the controlled sequence that hashes to the same bucket as key and has equivalent ordering to key. If no such element exists, or if X is the last element in the controlled sequence, it returns hash_map::end; otherwise it returns an iterator that designates the first element beyond X. You use it to locate the end of a sequence of elements currently in the controlled sequence that match a specified key.

Essentially, these functions allow you to identify the range of elements that have a given key. Their behavior is not the same as the behavior of std::lower_bound or std::map::lower_bound (theirs is the behavior that you were expecting).

For what it's worth, the C++0x unordered associative containers do not provide lower_bound, upper_bound, or equal_range functions.

Would you have any suggestion on what I could use for my requirement?

Yes: if you need the behavior of lower_bound and upper_bound, use an ordered associative container like std::multimap.

James McNellis
@james-mcnellis Thanks for your answer. Your suggestion to use std::multimap instead of the stdext::hash_multimap worked. The reason I assumed that the three methods did what I thought was because of the following MSDN pages: http://bit.ly/aAGAlk, http://bit.ly/ammaLF, which are different than the ones you posted - the ones you posted seem to be for CLR (i.e. Managed code, not native code). The ones I posted are the same documentation that I have in my local MSDN install. It appears that Microsoft has a documentation flaw. But your explanation was more than sufficient to solve my problem.
ossandcad
@ossandcad: Oh, sorry about that. I quoted the `hash_map` documentation, not the `hash_multimap` documentation. Yes, the `hash_multimap` documentation is misleading at best. It says it returns an iterator "that addresses the location succeeding the last element in the hash_multimap if no match is found for the key." So, if no match for the key is found, it returns `end()`. The first part of that sentence (which I didn't quote here), though, is quite confusing.
James McNellis