Я хочу изменить элемент в наборе (QSet):
for(PSet::iterator pIt = P.begin(); pIt != P.end(); ++pIt)
pIt->xp = 0;
Компилятор не позволит мне это сделать ("C3892:" var ": вы не можете назначить переменную const). Кажется, что набор итераторов всегда постоянен из-за опасения, что изменение элемента может повредить его правильное положение в наборе.
В моем случае PSet - это набор структур, для которых я определил свою собственную хеш-функцию:
struct P
{
P(int id, const Data_t& data)
:xp(_INFINITY_)
,id(id)
,data(data){}
int xp;
const int id;
const Data_t data;
};
Моя хеш-функция не учитывает неконстантный член xp, поэтому мое вышеприведенное назначение должно быть абсолютно безопасным относительно порядка элементов в наборе. Я не хочу удалять элемент и повторно вставлять его, поскольку производительность на самом деле является проблемой.
Думаю, я мог бы использовать const-casts, но это ухудшило бы мою читаемость кода и выглядело бы как неприятный хак. Есть ли у меня другие варианты?
Изменение элементов QSet
недопустимо, поскольку оно может нарушить заданную внутреннюю структуру контейнера, изменив один из хэш-результатов.
Что касается стандартных ассоциативных контейнеров, то это в стандартном разделе § 23.2.4
итератор ассоциативного контейнера относится к категории двунаправленного итератора. Для ассоциативных контейнеров, где тип значения совпадает с типом ключа, оба итератора и const_iterator являются постоянными итераторами. Не указано, является ли итератор и const_iterator одним и тем же типом.
Если вы знаете, что ваша модификация не влияет на элемент отсортированной позиции, использование const_cast
является одним из тех редких случаев, когда это нормально.
Однако, идиоматическим способом является использование подсказки:
QSet
)Пример:
s.erase(original);
// modify p ...
s.insert(copy, hint);
Заметки:
std::vector
заменой std::set
Элементы set
не могут быть дублирующими. Если вам будет разрешено изменить элемент, тогда вся эта логика не будет сохранена. Поэтому вам нужно удалить существующий элемент и вставить новый.
Поэтому, если вы не используете const_cast
, нет другого способа сделать это. Однако, как уже упоминалось, это может нарушить set
, позволяя ему иметь потенциальные повторяющиеся значения.
Вот как это сделать для std::set<int>
(я знаю, что это не набор QT, но логика должна быть одинаковой):
std::set<int> mySet;
mySet.insert(3);
mySet.insert(4);
for (auto i = mySet.begin(); i != mySet.end(); i++)
{
int* elem = const_cast<int*>(&*i);
*elem = 6;
}