Есть ли проблема с использованием строки C в качестве ключа карты?
std::map<const char*, int> imap;
Порядок элементов на карте не имеет значения, поэтому все в порядке, если они упорядочены с использованием std::less<const char*>
,
Я использую Visual Studio и в соответствии с MSDN (Microsoft):
В некоторых случаях идентичные строковые литералы могут быть «объединены» для экономии места в исполняемом файле. В пуле строковых литералов компилятор заставляет все ссылки на определенный строковый литерал указывать на одно и то же место в памяти, вместо того, чтобы каждая ссылка указывала на отдельный экземпляр строкового литерала.
Это говорит о том, что они только объединены в некоторых случаях, так что кажется, что получить доступ к элементам карты с помощью строкового литерала было бы плохой идеей:
//Could these be referring to different map elements?
int i = imap["hello"];
int j = imap["hello"];
Можно ли перегрузить operator==
за const char*
так что фактическая строка C, а не значения указателя будет использоваться для определения, равны ли элементы карты:
bool operator==(const char* a, const char* b)
{
return strcmp(a, b) == 0 ? true : false;
}
Является ли когда-нибудь хорошей идеей использовать строку C в качестве ключа карты?
Можно ли перегрузить оператор == для const char *, чтобы фактическая строка C, а не значения указателя использовались для определения, равны ли элементы карты
Нет, это не так, и да, это не очень хорошая идея именно по той причине, которая указана в вопросе. а также потому что тебе не нужно char*
Вы можете использовать std::string
вместо. (вы можете предоставить пользовательскую функцию сравнения — как указано в simonc, но я бы посоветовал против этого)
//Could these be referring to different map elements?
int i = imap["hello"];
int j = imap["hello"];
Да, и они могут даже ссылаться на элементы, которые еще не существуют, но они будут созданы operator[]
и значение будет инициализировано. Та же проблема существует с назначением:
imap["hello"] = 0;
imap["hello"] = 1;
Карта теперь может иметь 1 или 2 элемента.
Вы можете предоставить карту с пользовательским компаратором, который сравнивает строки C
std::map<const char*,YourType,CstrCmp>;
bool CstrCmp::operator()(const char* a, const char* b)
{
return strcmp(a, b) < 0;
}
Во-первых, чтобы ввести упорядочение по ключам карты, необходимо определить сравнение «меньше, чем». Карта говорит, что два элемента «эквивалентны», если ни один не меньше другого. Это плохая идея использовать char * для ключей карты, потому что вам нужно будет управлять памятью где-то за пределами карты.
В большинстве реалистичных сценариев при запросе карты ваши ключи не будут литералами.
С другой стороны, если вы поддерживаете пул строковых литералов самостоятельно и назначаете идентификатор каждому литералу, вы можете использовать эти идентификаторы для ключей карты.
Подводя итог, я бы не стал полагаться на то, что Microsoft говорит: «В некоторых случаях литералы могут объединяться». Если вы заполняете карту литералами и запрашиваете карту с литералами в качестве ключей, вы также можете использовать enum для ключей.