Есть ли хороший способ сделать то, что я хочу?
Нет, не совсем. Гранулярность std::set
находится на уровне объекта. express невозможно, чтобы часть объекта вносила вклад в ключ.
Некоторые люди рекомендуют объявлять все неключевые элементы mutable
. Это неправильно, так как mutable
предназначен для вещей, которые скрыты от интерфейса объекта publi c (например, мьютекс).
"Официальный" способ - вывести объект из набора , измените его и вставьте обратно. C ++ 17 имеет set::extract
, что немного улучшает производительность этой задачи (что, конечно, остается неэффективным, если вы никогда не модифицируете ключ, так как дерево все еще должен быть проверен / перебалансирован).
Я хочу "использовать" объекты для выполнения других действий, которые могут изменить их элементы.
Если вы абсолютно уверены, что никогда не изменяете ключ объекта, просто отбросьте const
ness. С юридической точки зрения нормально отбрасывать постоянство от объектов, которые не родились const
. Для дополнительной безопасности вы можете заключить ключ в другой член const
:
struct Element {
const Key key;
Value value;
};
Это не поможет, если у вас есть куб данных с несколькими наборами, каждый из которых использует свое собственное «представление» ключа.
1. Сохраните unique_ptr
s для объекта в set
Это будет пессимизацией из-за дополнительного косвенного обращения. Так как элементы находятся в куче, вы получите дополнительную потерю кеша. И снова получите UB, если вы случайно измените ключ.
2. Сохраните map
, используя id()
в качестве ключа
Да, возможны различные варианты этого подхода, но вы все равно должны убедиться, что никогда не модифицируете ключ.
Например, вы можете сохранить ключ + указатель на данные. Этот подход часто сочетается с density_hash_set с линейным зондированием для лучшей производительности. Поскольку к значению обращаются только один раз после того, как элемент найден, не имеет значения, находится ли он где-либо еще.