Информация об изменениях

Сообщение Re[3]: Засада с эквивалентным ключом в std::unordered_map от 17.10.2024 15:13

Изменено 17.10.2024 18:35 watchmaker

Re[3]: Засада с эквивалентным ключом в std::unordered_map
Здравствуйте, andyp, Вы писали:

A> Вот сейчас в с++20 введут прозрачные хешеры и компараторы, а проблема-то частично останется — ты для того, что ищешь, будешь всегда считать хеш. Платишь за то, что тебе не уперлось из-за кривого интерфейса.


Интерфейс, конечно, кривой. Но прозрачные хеши как раз уже сейчас позволяют не считать хеш повторно от констант.

В программе ты сам делаешь выбор: считать ли хэш от string_view каждый раз, либо посчитать его однажды и положить рядом:
// строка + хэш
struct hashed_string_view: std::string_view {
    constexpr hashed_string_view(std::string_view v);
    size_t cached_hash = 0;
};

Так потратишь несколько лишних байт, но зато вычисление хэша очень будет быстрым: return this->cached_hash;. Это бывает само по себе полезено, например, когда объекты большие и хэш от них считается медленно.

И в комбинации с прозрачным хэшированием такой класс отлично работает:
struct string_hash {
    using is_transparent = void;
    constexpr std::size_t operator()(const std::string_view str) const { return my_hash_impl(str); }   // вычисляем хэш динамически
    constexpr std::size_t operator()(const hashed_string_view& str) const { return str.cached_hash; }  // достаём предпосчитанное значение
};

consteval hashed_string_view operator""_svh(const char* str, size_t len) {
    return hashed_string_view{std::string_view{str, len}};
}


Теперь, если использовать string_hash в качестве хэшера для мапы, то от констант значение хэша будет посчитано сразу:
std::unordered_multimap<std::string, ValueType, string_hash, std::equal_to<>> map;

auto it = map.find("key"_svh");
Демо и сравнение.

A> проблема-то частично останется


Хотя упрёк справедливый, потому из коробки не работает:
  1. В старом коде нужно включать поддержку прозрачности явно из-за пароноидальной обратной совместимости;
  2. Готового mixin-класса для кэширования хэшей в стандартной библиотеки нет;
  3. Хэш функцию тоже нужно посдавлять свою, из-за возможности рандомизации (скорее гипотетической) std::hash<string_view>, из-за чего её в общем случае нельзя вычислять от константных литералов во время компиляции.
Каждый пункт решается в одно-две строчки, но этого уже достаточно, чтобы куча кода так и оставалось работать с неэффектиными значениями по умолчанию.