Eu tenho dois std::map<>
objetos a
e b
gostaria de mover ( extract
+ insert
) alguns elementos (nós) de um mapa para outro com base em algum predicado p
.
for (auto i = a.begin(); i != a.end(); ++i)
if (p(*i))
b.insert(a.extract(i))
Esse código é segmentado em clang. Suponho que o problema é o incremento de i
depois que seu nó foi extraído de um.
É a maneira correta / única de corrigir isso usando um pós-incremento ?, Por exemplo:
for (auto i = a.begin(); i != a.end();)
if (p(*i))
b.insert(a.extract(i++))
else
++i;
Edição : Eu removi a parte sobre "por que isso funciona no gcc?", Porque não consigo reproduzir isso na minha configuração atual. Estou convencido de que isso costumava acontecer em algum momento, mas com o gcc 9.2.1 eu recebo um impasse (em vez de um segfault). De qualquer forma, incrementar depois extract()
não está funcionando.
std::set
estd::map
são muito semelhantes, e até onde eu sei,extract
tem as mesmas implicações de invalidação queerase
.Respostas:
De fato. A extração invalida os iteradores para o elemento extraído e
i
é esse iterador. O comportamento de incrementar ou indiretamente por meio de um iterador inválido é indefinido.Porque o comportamento do programa é indefinido.
É uma maneira correta de corrigir isso. Não é um caminho particularmente ruim. Se você preferir não repetir o incremento, uma abordagem é usar uma variável:
fonte
current
seria deixado em um estado movido. Qualquer que seja esse estado, não importará, pois não será mais usado depois disso.current
usando aif (auto current = ++i; p(*current))
sintaxe c ++ 17s .