Aquí está mi código:
while (it!=s.end()) //here 's' is a set of stl and 'it' is iterator of set
{
*it=*it-sub; //'sub' is an int value
it++;
}
No puedo actualizar el valor de establecer por iterador. Quiero restar un valor entero 'sub' de todos los elementos del conjunto.
¿Alguien puede ayudarme dónde está el problema real y cuál sería la solución real?
Aquí está el mensaje de error:
error: assignment of read-only location ‘it.std::_Rb_tree_const_iterator<int>::operator*()’
28 | *it=*it-sub;
| ~~~^~~~~~~~
*it - sub
. Tenga en cuenta questd::set::erase()
devuelve un nuevo iterador que debe usarse en su caso para mantener elwhile
bucle funcionando correctamente.Respuestas:
Los valores clave de los elementos en a
std::set
sonconst
por una buena razón. Modificarlos puede destruir el orden que es esencial para astd::set
.Por lo tanto, la solución es borrar el iterador e insertar uno nuevo con la clave
*it - sub
. Tenga en cuenta questd::set::erase()
devuelve un nuevo iterador que debe usarse en su caso para mantener el bucle while funcionando correctamente.Salida:
Demo en vivo en coliru
Los cambios al
std::set
iterar sobre él no son un problema en general, pero pueden causar problemas sutiles.El hecho más importante es que todos los iteradores usados deben mantenerse intactos o ya no pueden usarse. (Es por eso que el iterador actual del elemento de borrado se asigna con el valor de retorno del
std::set::erase()
cual es un iterador intacto o el final del conjunto).Por supuesto, los elementos se pueden insertar también detrás del iterador actual. Si bien esto no es un problema relacionado con el
std::set
, puede romper el ciclo de mi ejemplo anterior.Para demostrarlo, cambié un poco la muestra anterior. Tenga en cuenta que agregué un contador adicional para otorgar la terminación del ciclo:
Salida:
Demo en vivo en coliru
fuente
std::set
. Puede ser necesario considerar el caso límite en el que el nuevo iterador se inserta directamente detrás del borrado. - Se omitirá después de la inserción en el bucle.extract
nodos, modificar sus claves y volverlos a configurar. Sería más eficiente, ya que evita asignaciones innecesarias.std::set
. Como no puede tener el mismo elemento dos veces, la inserción solo dejará elstd::set
mismo y perderá el elemento más tarde. Considere, por ejemplo, el conjunto de entrada:{10, 20, 30}
conadd = 10
.Simple simplemente reemplazarlo con otro conjunto
fuente
No puede mutar elementos de
std::set
diseño. Verhttps://en.cppreference.com/w/cpp/container/set/begin
Eso es porque el conjunto está ordenado . Si muta un elemento en una colección ordenada, la colección debe ordenarse nuevamente, lo que por supuesto es posible, pero no de la manera C ++.
Sus opciones son:
std::set
, modifíquelo, luego insértelo nuevamente. (No es una buena idea si desea modificar cada elemento)fuente
A
std::set
se implementa típicamente como un árbol binario de equilibrio automático en STL.*it
es el valor del elemento que se usa para ordenar el árbol. Si fuera posible modificarlo, el pedido se volvería inválido, por lo tanto, no es posible hacerlo.Si desea actualizar un elemento, debe encontrar ese elemento en el conjunto, eliminarlo e insertar el valor actualizado del elemento. Pero como debe actualizar los valores de todos los elementos, debe borrar e insertar todos los elementos uno por uno.
Es posible hacerlo en uno para el bucle proporcionado
sub > 0
.S.erase(pos)
elimina el iterador en la posiciónpos
y devuelve la siguiente posición. Sisub > 0
, el valor actualizado que insertará vendrá antes del valor en el nuevo iterador en el árbol pero sisub <= 0
, entonces el valor actualizado vendrá después del valor en el nuevo iterador en el árbol y, por lo tanto, terminará en un Bucle infinito.fuente
El error explica más o menos el problema.
Los miembros del
std::set
contenedor sonconst
. Al cambiarlos, sus respectivos pedidos no son válidos.Para cambiar elementos
std::set
, tendrá que borrar el elemento y volver a insertarlo después de cambiarlo.Alternativamente, podría usar
std::map
para superar este escenario.fuente