Re: map.find doesn't find
On 12 Mar 2007 23:21:28 -0700, "aleko" <aleko.petkov@gmail.com> wrote:
Hi,
I ran into an interesting problem yesterday with STL's map, and I'm
hoping someone would help me understand what's going on.
Basically the map.find() method fails to find a match for a key that I
know is in the map. I followed the code to the == operator, and was
quite surprised to find this:
bool operator==(const const_iterator& _Right) const
{
...
return (_Ptr == _Right._Ptr); // ?!
}
The method is comparing pointers to determine if the objects are
equal! In my case the map key is of type const wchar_t* so this is
definitely not what I want. Below is some code that creates a map,
adds a key/value pair, and then tries to find it.
struct SCmdInfo;
typedef int (*TCommandProc)( const SCmdInfo& cmd );
typedef std::map<const wchar_t*, TCommandProc> TCmdMap;
TCmdMap cmdMap;
cmdMap[L"dir"] = cmd_dir;
TCmdMap::iterator it = cmdMap.find( L"dir" ); // it == cmdMap.end()
What am I doing wrong?
The operator== is for the iterator type, not your key_type; moreover,
operator== isn't used to compare keys. In order to compare strings, you'd
be better off using std::wstring. If you want to continue using wchar_t*,
you will need to provide an appropriate comparison predicate, such as:
struct CompWideStrings
{
bool operator()(const wchar_t* x, const wchar_t* y) const
{
return wcscmp(x, y) < 0;
}
};
typedef std::map<const wchar_t*, TCommandProc, CompWideStrings> TCmdMap;
See the map documentation for more:
http://msdn2.microsoft.com/en-us/library/s44w4h2s(VS.80).aspx
If you were to store std::wstring, the comparison would be handled by the
default std::less, which is wrong for comparing wchar_t* strings because it
simply compares the pointers, as you've already discovered. Another reason
std::wstring may be better is lifetime management. Again, this will be
handled automatically if you use std::wstring, but if you use wchar_t*, you
will have to ensure the strings you store in the map outlive the map's use
of them. On the other hand, saying things like:
TCmdMap::iterator it = cmdMap.find( L"dir" ); // it == cmdMap.end()
when the key is a std::wstring requires creation of a temporary wstring,
which is inefficient and not exception-safe. Of course, you can fix that by
using static duration constant wstrings instead of string literals.
--
Doug Harrison
Visual C++ MVP