Есть ли контейнер С++, который может обрабатывать изменение методов хеширования/сравнения/равенства?

У меня есть класс, которым управляет std::shared_ptr. Этот класс имеет хеш и все операторы ==, < и т.д. Для простоты предположим, что это класс int. Что мне нужно, так это реестр всех int, используемых в настоящее время, который не будет поддерживать их в рабочем состоянии дольше, чем необходимо, и имеет быстрый (быстрый, чем линейный) поиск. Это будет использоваться, чтобы гарантировать, что я не создам два разных объекта int с одним и тем же номером, например. прежде чем создавать новый 42, я проверю, существует ли уже 42 в реестре. Кажется, я хочу что-то вроде Java WeakHashMap?

Одно из возможных решений — использовать std::unordered_set<std::shared_ptr<int>> и периодически перебирать набор и удалять все элементы, у которых shared_ptr::use_count() равно 1. Это работает, но не идеально, поскольку объекты остаются живыми дольше, чем им нужно.

Или я мог бы использовать std::vector<std::weak_ptr<int>>, который освобождал бы немедленно, но требовал бы итерации по всему вектору каждый раз, когда я хочу увидеть, существует ли конкретный int (медленно).

std::unordered_set<std::weak_ptr<int>> удовлетворит обоим моим требованиям, за исключением того факта, что хэши должны будут измениться после истечения срока действия weak_ptr, и "Container elements may not be modified since modification could change an element's hash and corrupt the container".

Есть ли контейнер с быстрым поиском, который может обрабатывать изменяющиеся хэши? Имейте в виду, что ему не нужно находить элементы, которые изменились, он просто не должен быть поврежден ими.


person imMAW    schedule 25.07.2020    source источник
comment
Возможно, вам нужно что-то вроде кэширования LRU или TLRU. Обычно реализуется с помощью хеш-таблицы и двусвязного списка. См. einarwh.wordpress.com/2011/04/13/. a-simple-lru-cache   -  person Sergey Dyshko    schedule 25.07.2020
comment
@ Мануэль, возможно, моя аналогия с «int» здесь немного не работает, но этот объект большой и дорогой. std::map<int, std::weak_ptr<int>> требует хранения копии int в качестве ключа, который не будет освобожден, когда все ссылки исчезнут. @SergeyDyshko, читаю это сейчас.   -  person imMAW    schedule 25.07.2020
comment
@imMAW, ты не можешь взять ключ? Это не обязательно должен быть весь объект, просто его подмножество. Как вы их сравниваете?   -  person Manuel    schedule 25.07.2020
comment
@Manuel Для точного сравнения требуется весь объект, но вместо этого в качестве ключа можно использовать хэш. Я думаю, что в соответствии с вашими мыслями, std::multimap<hash, std::weak_ptr<int>> может помочь (мультимап в случае коллизии хэшей).   -  person imMAW    schedule 25.07.2020
comment
Зачем вам менять хеш после истечения срока его действия? Разве вы не можете просто проверить, существует ли он и не просрочен ли ваш чек?   -  person super    schedule 25.07.2020
comment
@super Предполагая, что вы говорите о std::unordered_set<std::weak_ptr<int>>, я не хочу, чтобы хэш изменился, я не смогу вычислить старый хеш. Мне нужно предоставить unordered_set хеш-функцию, которая принимает std::weak_ptr<int>. Я мог бы реализовать это, выполнив: if unexpired, return the hash of the int. else if expired, return 0. По истечении срока действия weak_ptr хеш-функция не сможет получить целое число и не сможет вычислить старый хэш. Но кажется, что unordered_set столкнется с проблемами, если я использую эту хеш-функцию.   -  person imMAW    schedule 25.07.2020
comment
@imMAW Вам нужно только вычислить хэш при вставке. Тогда не изменится. Что вы имеете в виду, что не сможете вычислить старый хэш? Кроме того. Если вы хотите проверить, существует ли 42 на карте перед ее созданием, по вашей аналогии 42 является объектом. Так как же узнать, существует ли объект уже до его создания?   -  person super    schedule 25.07.2020
comment
@super Я планирую создать дубликат 42 для поиска, а затем немедленно уничтожить его, если он уже существует. Не идеально, но в любой момент будет максимум один ненужный объект, занимающий память. Что касается изменяющегося хэша - хэш объекта в set может быть пересчитан в любое время, когда set пожелает это сделать, и он ожидает, что хэш каждый раз будет одним и тем же. Смотрите самый нижний ответ здесь для уточнения: вычисление хэша должно быть стабильным title="почему 32769-я вставка не работает в stdunordered set"> stackoverflow.com/questions/50402508/   -  person imMAW    schedule 25.07.2020
comment
С std::unordered_set<std::weak_ptr<int>> «объект в set» является std::weak_ptr<int>, поэтому unordered_set будет ожидать, что std::weak_ptr<int> будет хешировать точно одно и то же каждый раз, когда он хэшируется. При вставке моя хеш-функция сможет правильно хешировать weak_ptr to 42, но если она захочет перехешировать после того, как станет weak_ptr to nothing, я не смогу вернуть правильный хэш.   -  person imMAW    schedule 25.07.2020
comment
Я думаю, что работа с std::multimap<hash, std::weak_ptr<int>> решит все проблемы. По сути, он кэширует хеш, поэтому всякий раз, когда он хочет пересчитать хеш, ему не нужно проходить через weak_ptr. Это просто означает, что мне нужно вручную вызывать хеш во время вставки/поиска, а не позволять контейнеру вызывать хэш за меня.   -  person imMAW    schedule 25.07.2020
comment
Это будет использоваться, чтобы гарантировать, что я не создам два разных объекта int с одним и тем же номером, например. прежде чем я создам новый 42, я проверю, существует ли уже 42 в реестре Так что эта часть вашего вопроса просто неверна, я думаю? В любом случае хранение хэша и объекта отдельно на карте кажется допустимым подходом, но тогда вы должны убедиться, что правильно справляетесь с коллизиями хэшей.   -  person super    schedule 25.07.2020