std :: map :: find (char *) не работает на 64-битной машине в режиме отладки - PullRequest
1 голос
/ 05 августа 2009

Я сталкиваюсь с интересной ситуацией и хочу поделиться со всеми. Определенно, если кто-то может помочь, я буду благодарен!

#include "stdafx.h"
#include <map>

#define DEF_NAME1   "NAME1" 
#define DEF_NAME2   "NAME2" 
#define DEF_NAME3   "NAME3" 
#define DEF_NAME4   "NAME4" 

struct TInfo
{
    const char * TName;
    const char * TArray1[100];
    const char * TArray2[100];
};

typedef std::map<const char*, TInfo*> TInfoMap;
typedef std::pair<const char*,TInfo*> TInfoPair;

static TInfoMap tinfomap;

TInfo TInfoArray[] =
{
{DEF_NAME1,{""}, {""}},
{DEF_NAME2,{""}, {""}},
{DEF_NAME3,{""}, {""}},
{DEF_NAME4,{""}, {""}}
};

TInfoMap* GetTInfoMap()
{

for (int i = 0; i < 3 ; i++ )
    tinfomap.insert(TInfoPair(TInfoArray[i].TName,&TInfoArray[i]));

return &tinfomap;
}


int _tmain(int argc, _TCHAR* argv[])
{
char *name="NAME3";

TInfo* ptr = new TInfo();

TInfoMap* map1 = GetTInfoMap(); 

if ( map1->find(name) == map1->end() )
    printf("Not found");
else
    printf("Found!");

return 0;
}

Я на Windows 2003 Server 64bit. Я получаю вывод "Найдено!" когда я компилирую / запускаю эту программу в режиме Release, и вывод «Не найден», когда я компилирую / запускаю эту программу в режиме Debug.

Есть идеи?

С уважением,

Azher

Ответы [ 3 ]

6 голосов
/ 05 августа 2009

Попробуйте использовать std :: string в качестве ключа на карте. Проблема, когда вы используете char * в качестве ключа, map сравнивает адреса char *, а не их содержимое, как вы ожидаете. Если вы хотите использовать char * в качестве ключа, вам нужно создать экземпляр карты с предикатом сравнения для третьего аргумента шаблона.

Различие между конфигурацией Debug и Release здесь может быть объяснено, как хранятся строковые литералы const - то же самое или отдельное хранилище используется для той же строки

Ты не одинок ссылка

1 голос
/ 05 августа 2009

Компилятору не нужно выделять одно и то же ограничение символа в одной и той же памяти. Если у вас есть ограничение char в двух файлах cpp, адрес будет другим.

Одна из идей - изменить карту на std :: map или объявить с помощью специального сравнения:

class CompareCString
{
  bool operator()(const char* one,const char* two) { return strcmp(one,two)>0; };
};
typedef std::map<const char*, TInfo*, CompareCString> TInfoMap;

Этот компаратор намного медленнее, чем просто сравнение двух указателей. Вы можете сохранить указатель в статическом ограничении.

#define DEFINE_NAME(X)   const char * X = #X ;
DEFINE_NAME(NAME1)
DEFINE_NAME(NAME2)
TInfo TInfoArray[] =
{
  {NAME1,{""}, {""}},
  {NAME2,{""}, {""}},
};

Использование:

map1->find(NAME1); // it should work.

Вы также можете создать массив const char * и изменить указатель cstring на указатель на идентичную cstring, найденную в этом массиве. Использование set - хорошая идея:

typedef set<const char *,CompareCString> IternStringSet;
const char* iternStringSetData[] = 
{
   "Name1","Name2","Name3","Name4"
};
enum IternStringNames
{
   Name1,Name2,Name3,Name4
};
IternStringSet iternStringSet(iternStringSetData,iternStringSetData+4);
const char* intern(const char* name)
{
     IternStringSet::iterator i = iternStringSet.find(name);
     return ( i=!iternStringSet.end() ) ? *i : NULL;
}
const char* intern(IternStringNames name)
{
     return iternStringSetData[name];
}

Использование:

const char* what = intern("Name1"); slower ,using strcmp, but done once
map1->find( what ); // faster, not using strcmp

map1->find( intern(Name1) ); // faster, not using strcmp
0 голосов
/ 05 августа 2009

Я только что попробовал это на моем 64-битном сервере server2008, и отладка и выпуск печати "Found!".

Так что, вероятно, вопрос 2003 года какого-то рода. У меня нет 64-битной версии 2003, так что не могу попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...