• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 219
  • Last Modified:

ATL and <map>

Ive got problems trying to build a map<_TCHAR *, _TCHAR *>

First, I'll write my code:
     typedef map<_TCHAR *, _TCHAR *> type_Data;
     typedef type_Data::value_type vtItem;
   
      type_Data object;
      type_Data::iterator it;

if i build the map using variables, that is:
_TCHAR object_insert1[]="Item 1";
_TCHAR object_insert2[]="Item 2";
_TCHAR object_insert3[]="Item 3";
_TCHAR object_insert4[]="Item 4";
object.insert(vtItem(object_insert1,_T("VALUE_1")));
object.insert(vtItem(object_insert2,_T("VALUE_2")));
object.insert(vtItem(object_insert3,_T("VALUE_3")));
object.insert(vtItem(object_insert4,_T("VALUE_4")));

and i try to find an item using another variable,

_TCHAR object_find[]="Item 2";
it = object.find(object_find);

it doesn't find anything;

But if i build the map using strings without variables, that is:

object.insert(vtItem(_T("Item 1"),_T("VALUE_1")));
object.insert(vtItem(_T("Item 2"),_T("VALUE_2")));
object.insert(vtItem(_T("Item 3"),_T("VALUE_3")));
object.insert(vtItem(_T("Item 4"),_T("VALUE_4")));

 I find any of the items i'm looking for.

Does anyone know what's the problem?
0
Moony
Asked:
Moony
  • 7
  • 5
1 Solution
 
jasonclarkeCommented:
The problem is that you are storing pointers in the map, so the test made using find will do pointer comparison, hence typically, you will not find them.

You need something like this:

struct tstr_equal
{
  TSTR* mValue;
  tstr_equal(TSTR* s) : mValue(s) {}
  bool operator()(pair<const K, V> elem)
  {
     return wcscmp( elem->second, mValue ) == 0;
     // or however you compare TSTRs...
  }
};


then

it = find_if(object.begin(), object.end(),
             tstr_equal(object_find));

0
 
ShaunWildeCommented:
try typing your map

typedef map<string, string> type_Data;
0
 
jasonclarkeCommented:
> try typing your map
> typedef map<string, string> type_Data;

wouldn't be very useful if unicode strings were being stored.
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
jasonclarkeCommented:
There were a few mistakes in the code I presented earlier, but here is a complete example that demonstrates the technique:

#pragma warning(disable:4786)

#include <tchar.h>
#include <map>
#include <algorithm>

using namespace std;

struct tstr_equal
{
 _TCHAR* mValue;

 tstr_equal(_TCHAR* s) : mValue(s) {}

 bool operator()(pair<_TCHAR *, _TCHAR *> elem)
 {
    return _tcscmp( elem.first, mValue ) == 0;
 }
};

int main()
{
    typedef map<_TCHAR *, _TCHAR *> type_Data;
    typedef type_Data::value_type vtItem;
   
    type_Data object;
    type_Data::iterator it;

    _TCHAR object_insert1[]="Item 1";
    _TCHAR object_insert2[]="Item 2";
    _TCHAR object_insert3[]="Item 3";
    _TCHAR object_insert4[]="Item 4";
    object.insert(vtItem(object_insert1,_T("VALUE_1")));
    object.insert(vtItem(object_insert2,_T("VALUE_2")));
    object.insert(vtItem(object_insert3,_T("VALUE_3")));
    object.insert(vtItem(object_insert4,_T("VALUE_4")));

    _TCHAR object_find[]="Item 2";
    it = find_if(object.begin(), object.end(), tstr_equal(object_find));

    _TCHAR* key = it->first;
    _TCHAR* value = it->second;

    return 0;
}
0
 
MoonyAuthor Commented:
Wow! Your answer was perfect! Thank you very much!
0
 
ShaunWildeCommented:
> wouldn't be very useful if unicode strings were being stored.

#ifdef _UNICODE
#define wstring string
#endif

no problem
0
 
jasonclarkeCommented:
> no problem

maybe, maybe not.  Many programs do not have the luxury of being able to operate entirely in one character set or another.  This kind of #define makes it impossible to use string for its plain ASCII text usage.
0
 
ShaunWildeCommented:
picky picky

typedef map<wstring, wstring> type_Data;

now we handle unicode strings

0
 
jasonclarkeCommented:
> typedef map<wstring, wstring> type_Data;

still not really good enough, since the problem with TCHAR is that you don't know whether it will be wide until run-time, so you would have to do something like:

#ifdef _UNICODE
    typedef map<wstring, wstring> type_Data;
#else
    typedef map<string, string> type_Data;
#endif

Which, I agree does make life somewhat simpler.  Using pointers is probably more troublesome in general.  

But, having said that, it is possible to store TCHAR pointers directly in the map.  The use is just a bit more complicated, and somewhat less efficient.
0
 
jasonclarkeCommented:
> whether it will be wide until run-time

I meant compile time rather than run time....
0
 
ShaunWildeCommented:
typedef basic_string<wchar_t> wstring;

and as I understand it wchar_t is a 'unsigned short' (see stddef.h) so by using wstring you know it is a wide string (unicode) - and since you solution used TCHAR then the same could be said about your own proposed solution
0
 
jasonclarkeCommented:
> and since you solution used TCHAR

not sure I understand your comment...

but the actual type of TCHAR depends on the system settings, i.e. if UNICODE, TCHAR = wchar_t, otherwise TCHAR = char.  

An advantage of using TCHARs directly is that maybe it makes it obvious that conversion *MAY* always be needed, it might be less easy to forget to do the conversion.
0
 
ShaunWildeCommented:
typedef basic_string<TCHAR> tstring;

its really not hard to apply the stl templates

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 7
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now