Aqui está o meu 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++;
}
Não consigo atualizar o valor de definido pelo iterador. Eu quero subtrair um valor inteiro 'sub' de todo o elemento do conjunto.
Alguém pode me ajudar onde está o problema real e qual seria a solução real?
Aqui está a mensagem de erro:
error: assignment of read-only location ‘it.std::_Rb_tree_const_iterator<int>::operator*()’
28 | *it=*it-sub;
| ~~~^~~~~~~~
*it - sub
. Observe questd::set::erase()
retorna um novo iterador que deve ser usado no seu caso para manter owhile
loop funcionando corretamente.Respostas:
Os principais valores dos elementos em a
std::set
sãoconst
por um bom motivo. Modificá-los pode destruir a ordem que é essencial para astd::set
.Portanto, a solução é apagar o iterador e inserir um novo com a chave
*it - sub
. Observe questd::set::erase()
retorna um novo iterador que deve ser usado no seu caso para manter o loop while funcionando corretamente.Resultado:
Demonstração ao vivo no coliru
As alterações
std::set
durante a iteração sobre ele não são um problema em geral, mas podem causar problemas sutis.O fato mais importante é que todos os iteradores usados devem ser mantidos intactos ou não podem mais ser usados. (É por isso que o iterador atual do elemento de apagamento é designado com o valor de retorno
std::set::erase()
que é um iterador intacto ou o final do conjunto.)Obviamente, é possível inserir elementos também atrás do iterador atual. Embora isso não seja um problema,
std::set
ele pode quebrar o loop do meu exemplo acima.Para demonstrá-lo, alterei um pouco a amostra acima. Observe que eu adicionei um contador adicional para conceder o término do loop:
Resultado:
Demonstração ao vivo no coliru
fonte
std::set
. Pode ser necessário considerar o caso de borda em que o novo iterador é inserido diretamente atrás do apagado. - Será ignorado após a inserção no loop.extract
nós, modificar suas chaves e retorná-las ao conjunto. Seria mais eficiente, pois evita alocações desnecessárias.std::set
. Como você não pode ter o mesmo elemento duas vezes, a inserção deixará ostd::set
inalterado e você perderá o elemento mais tarde. Considere, por exemplo, o conjunto de entrada:{10, 20, 30}
withadd = 10
.Simples de substituí-lo por outro conjunto
fonte
Você não pode alterar os elementos
std::set
por design. Vejohttps://en.cppreference.com/w/cpp/container/set/begin
Isso ocorre porque o conjunto está classificado . Se você alterar o elemento em uma coleção classificada, a coleção deverá ser classificada novamente, o que é obviamente possível, mas não a maneira C ++.
Suas opções são:
std::set
, modifique-o e insira novamente. (Não é uma boa ideia se você deseja modificar todos os elementos)fonte
A
std::set
é normalmente implementado como uma árvore binária de auto-equilíbrio no STL.*it
é o valor do elemento que é usado para ordenar a árvore. Se fosse possível modificá-lo, o pedido se tornaria inválido, portanto, não é possível fazer isso.Se você deseja atualizar um elemento, é necessário encontrar esse elemento no conjunto, removê-lo e inserir o valor atualizado do elemento. Mas como você precisa atualizar os valores de todos os elementos, é necessário apagar e inserir todos os elementos, um por um.
É possível fazer isso em um loop for fornecido
sub > 0
.S.erase(pos)
remove o iterador na posiçãopos
e retorna a seguinte posição. Sesub > 0
o valor atualizado que você inserir será anterior ao valor no novo iterador na árvore, mas sesub <= 0
, então, o valor atualizado virá após o valor no novo iterador na árvore e, portanto, você terminará em um Loop infinito.fonte
O erro explica praticamente o problema
Os membros do
std::set
contêiner sãoconst
. Mudá-los invalida a respectiva ordem.Para alterar os elementos
std::set
, você precisará apagar o item e reinserir depois que ele for alterado.Como alternativa, você pode usar
std::map
para superar esse cenário.fonte