Существует ли стандартный механизм для получения хэша строки 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 спецификатор. В любом случае это было бы бесполезно, если данные хранятся где-то еще.

РЕДАКТИРОВАТЬ: Я только что понял, что пример алгоритма, который я представил, работает на узких строках. Я думаю, вы все еще можете найти тот, который работает с широкими символами.

Другие вопросы по тегам