Существует ли стандартный механизм для получения хэша строки C?
У меня есть строка C (wchar_t const*
) время жизни которого принадлежит какой-то другой структуре данных; ссылки на строку передаются по указателю. Я хочу поместить такие случаи в unordered_map
, Есть ли стандартный инструмент, который я могу использовать, чтобы получить хеш этого без создания временного std::wstring
и звонит std::hash<std::wstring>
?
Обратите внимание, что std::hash<T*>
возвращает хеш указателя, а не хеш содержимого потока байтов, на который указывает этот указатель.
1 ответ
Как вы заметили, и, как объясняется здесь, нет std::hash
специализация для струн в стиле C Цитируется со связанной страницы:
Там нет специализации для C строк.
std::hash<const char *>
создает хэш значения указателя (адрес памяти), он не проверяет содержимое какого-либо массива символов.
Таким образом, хеш-значение, создаваемое std::hash
Применительно к любой такой строке не связано с ее фактическим содержанием, и, следовательно, не подходит для целей, которые вам нужны.
Что ты можешь сделать? Создание временного объекта вне игры, поскольку оно может включать выделение, которое может привести к небезопасной исключительной ситуации, и всегда будет бесполезной копией. Как указано в комментарии выше user657267, если ваша стандартная библиотека поддерживает basic_string_view
следует также предоставить соответствующие std::hash
специализации, перечисленные на этой странице.
Наконец, вы можете запустить свой собственный алгоритм хеширования. Если значения хеш-функции будут использоваться в неупорядоченных контейнерах, качество алгоритма будет влиять на производительность, но не на уникальность ключей (т. Е. Не будет никаких коллизий; вы можете проверить это), как я обнаружил ранее. Этот пример реализует алгоритм X65599, который работал для меня:
#include <cstring>
struct
hasher final
{
constexpr std::size_t
operator()
( const char * const s )
const noexcept
{
std::size_t h = 0;
for ( std::size_t i = 0 , l = std::strlen(s) ; i < l ; ++i )
{
h += h * 65599 + s[i];
}
return h ^ (h >> 16);
}
};
Если ваш компилятор не поддерживает C++14, вы можете удалить constexpr
спецификатор. В любом случае это было бы бесполезно, если данные хранятся где-то еще.
РЕДАКТИРОВАТЬ: Я только что понял, что пример алгоритма, который я представил, работает на узких строках. Я думаю, вы все еще можете найти тот, который работает с широкими символами.