Я нахожу операцию обновления на std::set
утомительный с тех пор на cppreference нет такого API. Таким образом, то, что я в настоящее время делаю, является чем-то вроде этого:
//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);
В основном итератор возвращается Set
a const_iterator
и Вы не можете изменить его значение непосредственно.
Существует ли лучший способ сделать это? Или возможно я должен переопределить std::set
путем создания моего собственного (который я не знаю точно, как это работает..)
set
возвращает const_iterators
(в стандарте указано set
равен const
, и что set
и set
могут на самом деле быть того же типа - см. 23.2.4 / 6 в n3000.pdf), потому что это заказанный контейнер. Если он вернет обычный итератор
, вам будет разрешено изменять значение элементов из-под контейнера, потенциально изменяя порядок.
Ваше решение - это идиоматический способ изменения элементов в наборе
.
Обновление: Хотя на данный момент верно следующее, поведение считается дефектом и будет изменено в следующей версии стандарта.Как очень грустно.
Есть несколько моментов, которые сбивают с толку ваш вопрос.
std :: set
- это класс, поэтому он не может ничего возвращать. s.erase (iter)
, то iter
не является const_iterator
. erase
требует неконстантного итератора. std :: set
, которые возвращают итератор, возвращают неконстантный итератор, если набор также не является константой. Вам разрешено изменять значение элемента набора, если обновление не изменяет порядок элементов. Следующий код компилируется и отлично работает.
#include <set>
int main()
{
std::set<int> s;
s.insert(10);
s.insert(20);
std::set<int>::iterator iter = s.find(20);
// OK
*iter = 30;
// error, the following changes the order of elements
// *iter = 0;
}
Если ваше обновление изменяет порядок элементов, вам придется стереть и снова вставить.
В простом случае это можно сделать двумя способами:
mutable
для переменной, не являющейся частью ключа Key
Value
пара (и использовать std :: map
) Теперь вопрос для сложного случая: что происходит, когда обновление фактически изменяет ключ
часть объекта? Ваш подход работает, хотя я признаю, что это утомительно.
Вместо этого вы можете использовать std :: map
. Используйте часть Element
, которая влияет на порядок ключей, и поместите весь Element
в качестве значения. Будет некоторое незначительное дублирование данных, но вы получите более легкие (и, возможно, более быстрые) обновления.