Quais são as regras de invalidação do iterador para contêineres C ++?
De preferência em um formato de lista resumida.
(Observação: isso deve ser uma entrada para as Perguntas frequentes sobre C ++ do Stack Overflow . Se você quiser criticar a idéia de fornecer uma FAQ neste formulário, a postagem na meta que iniciou tudo isso seria o lugar para isso. essa pergunta é monitorada na sala de bate-papo do C ++ , onde a ideia das Perguntas frequentes começou em primeiro lugar; portanto, é muito provável que sua resposta seja lida por quem a teve.)
Respostas:
C ++ 17 (Todas as referências são do rascunho final do trabalho da CPP17 - n4659 )
Inserção
Contêineres de sequência
vector
: As funçõesinsert
,emplace_back
,emplace
,push_back
causa realocação se o novo tamanho é maior do que a capacidade de idade. A realocação invalida todas as referências, ponteiros e iteradores que se referem aos elementos na sequência. Se nenhuma realocação acontecer, todos os iteradores e referências antes do ponto de inserção permanecerão válidos. [26.3.11.5/1]Com relação à
reserve
função, a realocação invalida todas as referências, ponteiros e iteradores que se referem aos elementos na sequência. Nenhuma realocação deve ocorrer durante as inserções que ocorrem após uma chamadareserve()
até o momento em que uma inserção tornaria o tamanho do vetor maior que o valor decapacity()
. [26.3.11.3/6]deque
: Uma inserção no meio do deque invalida todos os iteradores e referências a elementos do deque. Uma inserção em cada extremidade do deque invalida todos os iteradores para o deque, mas não afeta a validade das referências a elementos do deque. [26.3.8.4/1]list
: Não afeta a validade dos iteradores e referências. Se uma exceção for lançada, não haverá efeitos. [26.3.10.4/1].A
insert
,emplace_front
,emplace_back
,emplace
,push_front
,push_back
funções são cobertos por esta regra.forward_list
: Nenhuma das sobrecargas deinsert_after
deve afetar a validade dos iteradores e referências [26.3.9.5/1]array
: Como regra , os iteradores para uma matriz nunca são invalidados durante toda a vida útil da matriz. Deve-se observar, no entanto, que durante a troca, o iterador continuará apontando para o mesmo elemento da matriz e, portanto, alterará seu valor.Contentores Associativos
All Associative Containers
: Os membrosinsert
eemplace
não devem afetar a validade dos iteradores e referências ao contêiner [26.2.6 / 9]Contêineres associativos não ordenados
All Unordered Associative Containers
: Rehashing invalida os iteradores, altera a ordem entre os elementos e as alterações nas quais elementos de buckets aparecem, mas não invalida ponteiros ou referências a elementos. [26.2.7 / 9]Os membros
insert
eemplace
não devem afetar a validade das referências aos elementos do contêiner, mas podem invalidar todos os iteradores do contêiner. [26.2.7 / 14]O
insert
eemplace
membros não afecta a validade da iterators se(N+n) <= z * B
, ondeN
é o número de elementos no recipiente, antes da operação de inserção,n
é o número de elementos inseridos,B
é contagem balde do recipiente, ez
é a fator de carga máxima do contêiner. [26.2.7 / 15]All Unordered Associative Containers
: No caso de uma operação de mesclagem (por exemplo,a.merge(a2)
), os iteradores referentes aos elementos transferidos e todos os iteradores referentesa
serão invalidados, mas os iteradores dos elementos restantesa2
permanecerão válidos. (Tabela 91 - Requisitos de contêiner associativo não ordenado)Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteErasure
Contêineres de sequência
vector
: As funçõeserase
epop_back
invalidam iteradores e referências no ponto ou após o apagamento. [26.3.11.5/3]deque
: Uma operação de exclusão que apaga o último elemento de umdeque
invalida apenas o iterador passado e todos os iteradores e referências aos elementos apagados. Uma operação de exclusão que apaga o primeiro elemento de um,deque
mas não o último, invalida apenas iteradores e referências aos elementos apagados. Uma operação de exclusão que apaga nem o primeiro elemento nem o último elemento de adeque
invalida o iterador passado-final e todos os iteradores e referências a todos os elementos dodeque
. [Nota:pop_front
epop_back
são operações de apagamento. - nota final] [26.3.8.4/4]list
: Invalida apenas os iteradores e referências aos elementos apagados. [26.3.10.4/3]. Isto aplica-seerase
,pop_front
,pop_back
,clear
funções.remove
eremove_if
funções-membro: Apaga todos os elementos da lista referidos por um iterador de listai
para os quais as seguintes condições são válidas:*i == value
,pred(*i) != false
. Invalida apenas os iteradores e referências aos elementos apagados [26.3.10.5/15].unique
função de membro - Apaga tudo, exceto o primeiro elemento de cada grupo consecutivo de elementos iguais referido pelo iteradori
no intervalo (para a versão de unique com um argumento predicado). Invalida apenas os iteradores e referências aos elementos apagados. [26.3.10.5/19][first + 1, last)
para o qual*i == *(i-1)
(para a versão de exclusivo sem argumentos) oupred(*i, *(i - 1))
forward_list
:erase_after
invalidará apenas iteradores e referências aos elementos apagados. [26.3.9.5/1].remove
eremove_if
funções-membro - Apaga todos os elementos na lista referidos por um iterador de lista i, para o qual as seguintes condições são válidas:*i == value
(forremove()
),pred(*i)
é verdadeiro (forremove_if()
). Invalida apenas os iteradores e referências aos elementos apagados. [26.3.9.6/12].unique
função membro - Apaga tudo, exceto o primeiro elemento, de cada grupo consecutivo de elementos iguais referido pelo iterador i no intervalo [primeiro + 1, último) para o qual*i == *(i-1)
(para a versão sem argumentos) oupred(*i, *(i - 1))
(para a versão com predicado) argumento) é válido. Invalida apenas os iteradores e referências aos elementos apagados. [26.3.9.6/16]All Sequence Containers
:clear
invalida todas as referências, ponteiros e iteradores que se referem aos elementos de a e pode invalidar o iterador passado-final (Tabela 87 - Requisitos do contêiner de sequência). Mas paraforward_list
,clear
não invalida os iteradores do passado. [26.3.9.5/32]All Sequence Containers
:assign
invalida todas as referências, ponteiros e iteradores referentes aos elementos do contêiner. Paravector
edeque
, também invalida o iterador passado. (Tabela 87 - Requisitos do contêiner de sequência)Contentores Associativos
All Associative Containers
: Oserase
membros invalidarão apenas iteradores e referências aos elementos apagados [26.2.6 / 9]All Associative Containers
: Osextract
membros invalidam apenas iteradores para o elemento removido; ponteiros e referências ao elemento removido permanecem válidos [26.2.6 / 10]Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteRequisitos gerais de contêiner relacionados à invalidação do iterador:
A menos que seja especificado de outra forma (explicitamente ou definindo uma função em termos de outras funções), invocar uma função de membro de contêiner ou passar um contêiner como argumento para uma função de biblioteca não invalidará os iteradores para, ou alterará os valores de, objetos dentro desse contêiner . [26.2.1 / 12]
nenhuma
swap()
função invalida quaisquer referências, ponteiros ou iteradores referentes aos elementos dos contêineres que estão sendo trocados. [Nota: O iterador end () não se refere a nenhum elemento, portanto pode ser invalidado. - nota final] [26.2.1 / (11.6)]Como exemplos dos requisitos acima:
transform
algoritmo: As funçõesop
ebinary_op
não devem invalidar iteradores ou subintervalos, nem modificar elementos nos intervalos [28.6.4 / 1]accumulate
algoritmo: no intervalo [primeiro, último],binary_op
não deve modificar elementos nem invalidar iteradores ou subintervalos [29.8.2 / 1]reduce
algoritmo: binary_op não invalida iteradores ou subintervalos, nem modifica elementos no intervalo [primeiro, último]. [29.8.3 / 5]e assim por diante...
fonte
std::string
? Eu acho que é diferentestd::vector
devido à SSOstring
falha no segundo requisito geral listado acima. Então eu não o incluí. Também tentei seguir o mesmo padrão das entradas anteriores da FAQ."invalidated" can mean "no longer points to what it used to", not just "may not point to any valid element"
como @Marshall Clow descrito nesta resposta ? Ou apenas indica apenas uma das duas condições?C ++ 03 (fonte: regras de invalidação do iterador (C ++ 03) )
Inserção
Recipientes de sequência
vector
: todos os iteradores e referências antes do ponto de inserção não são afetados, a menos que o novo tamanho do contêiner seja maior que a capacidade anterior (nesse caso, todos os iteradores e referências são invalidados) [23.2.4.3/1]deque
: todos os iteradores e referências são invalidados, a menos que o membro inserido esteja no final (frente ou verso) do deque (nesse caso, todos os iteradores são invalidados, mas as referências aos elementos não são afetadas) [23.2.1.3/1]list
: todos os iteradores e referências não afetados [23.2.2.3/1]Contêineres associativos
[multi]{set,map}
: todos os iteradores e referências não afetados [23.1.2 / 8]Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteErasure
Recipientes de sequência
vector
: todos os iteradores e referências após o ponto de exclusão são invalidados [23.2.4.3/3]deque
: todos os iteradores e referências são invalidados, a menos que os membros apagados estejam no final (frente ou verso) do deque (nesse caso, apenas iteradores e referências aos membros apagados são invalidados) [23.2.1.3/4]list
: apenas os iteradores e referências ao elemento apagado são invalidados [23.2.2.3/3]Contêineres associativos
[multi]{set,map}
: apenas iteradores e referências aos elementos apagados são invalidados [23.1.2 / 8]Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteRedimensionando
vector
: conforme inserir / apagar [23.2.4.2/6]deque
: conforme inserir / apagar [23.2.1.2/1]list
: conforme inserir / apagar [23.2.2.2/1]Nota 1
Nota 2
Não está claro no C ++ 2003 se os iteradores "finais" estão sujeitos às regras acima ; de qualquer maneira, você deve assumir que eles são (como é o caso na prática).
Nota 3
As regras para invalidação de ponteiros são os mesmos que as regras para invalidação de referências.
fonte
C ++ 11 (fonte: regras de invalidação do iterador (C ++ 0x) )
Inserção
Recipientes de sequência
vector
: todos os iteradores e referências antes do ponto de inserção não são afetados, a menos que o novo tamanho do contêiner seja maior que a capacidade anterior (nesse caso, todos os iteradores e referências são invalidados) [23.3.6.5/1]deque
: todos os iteradores e referências são invalidados, a menos que o membro inserido esteja no final (frente ou verso) do deque (nesse caso, todos os iteradores são invalidados, mas as referências aos elementos não são afetadas) [23.3.3.4/1]list
: todos os iteradores e referências não afetados [23.3.5.4/1]forward_list
: todos os iteradores e referências não afetados (se aplica ainsert_after
) [23.3.4.5/1]array
: (n / a)Contêineres associativos
[multi]{set,map}
: todos os iteradores e referências não afetados [23.2.4 / 9]Contêineres associativos não classificados
unordered_[multi]{set,map}
: todos os iteradores são invalidados quando ocorre a repetição, mas as referências não são afetadas [23.2.5 / 8]. A rehashing não ocorre se a inserção não fizer com que o tamanho do contêiner excedaz * B
ondez
está o fator de carga máximo eB
o número atual de caçambas. [23.2.5 / 14]Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteErasure
Recipientes de sequência
vector
: todo iterador e referência no ou após o ponto de exclusão são invalidados [23.3.6.5/3]deque
: apagar o último elemento invalida apenas os iteradores e as referências aos elementos apagados e ao iterador passado-final; apagar o primeiro elemento invalida apenas iteradores e referências aos elementos apagados; apagar qualquer outro elemento invalida todos os iteradores e referências (incluindo o iterador passado) [23.3.3.4/4]list
: apenas os iteradores e referências ao elemento apagado são invalidados [23.3.5.4/3]forward_list
: apenas os iteradores e referências ao elemento apagado são invalidados (aplica-se aerase_after
) [23.3.4.5/1]array
: (n / a)Contêineres associativos
[multi]{set,map}
: apenas iteradores e referências aos elementos apagados são invalidados [23.2.4 / 9]Contêineres associativos não ordenados
unordered_[multi]{set,map}
: apenas iteradores e referências aos elementos apagados são invalidados [23.2.5 / 13]Adaptadores de contêiner
stack
: herdado do contêiner subjacentequeue
: herdado do contêiner subjacentepriority_queue
: herdado do contêiner subjacenteRedimensionando
vector
: conforme inserir / apagar [23.3.6.5/12]deque
: conforme inserir / apagar [23.3.3.3/3]list
: conforme inserir / apagar [23.3.5.3/1]forward_list
: conforme inserir / apagar [23.3.4.5/25]array
: (n / D)Nota 1
Nota 2
Nota 3
Além da ressalva acima
swap()
, não está claro se os iteradores "finais" estão sujeitos às regras por contêiner listadas acima ; você deve assumir, de qualquer maneira, que são.Nota 4
vector
e todos os contêineres associativos não ordenados suportam,reserve(n)
garantindo que nenhum redimensionamento automático ocorra pelo menos até que o tamanho do contêiner aumenten
. Deve-se tomar cuidado com contêineres associativos não ordenados, porque uma proposta futura permitirá a especificação de um fator de carga mínimo, o que permitiria a repetição de tarefasinsert
apóserase
operações suficientes reduzir o tamanho do contêiner abaixo do mínimo; a garantia deve ser considerada potencialmente nula após umerase
.fonte
swap()
, quais são as regras para a validade do iterador na atribuição de copiar / mover?std::basic_string
não parece ser contado como um contêiner e, certamente, não é um contêiner na seção do padrão a que a nota se aplica. Ainda assim, onde diz que o SSO não é permitido (eu sei que o COW é)?É provavelmente vale a pena acrescentar que um iterador inserção de qualquer tipo (
std::back_insert_iterator
,std::front_insert_iterator
,std::insert_iterator
) é garantido para permanecer válido, desde que todas as inserções são realizadas através deste iterador e nenhum outro evento de invalidação iterador independente ocorre.Por exemplo, quando você está executando uma série de operações de inserção em um
std::vector
usandostd::insert_iterator
, é bem possível que essas inserções acionem a realocação de vetores, o que invalidará todos os iteradores que "apontam" para esse vetor. No entanto, o iterador de inserção em questão é garantido para permanecer válido, ou seja, você pode continuar com segurança a sequência de inserções. Não há necessidade de se preocupar em acionar a realocação de vetores.Isso, novamente, se aplica apenas às inserções executadas pelo próprio iterador de inserção. Se o evento de invalidação do iterador for acionado por alguma ação independente no contêiner, o iterador de inserção também será invalidado de acordo com as regras gerais.
Por exemplo, este código
é garantido para executar uma sequência válida de inserções no vetor, mesmo se o vetor "decidir" realocar em algum lugar no meio desse processo. O iterador
it
obviamente ficará inválido, masit_ins
continuará válido.fonte
Como essa pergunta atrai tantos votos e se torna um FAQ, acho que seria melhor escrever uma resposta separada para mencionar uma diferença significativa entre C ++ 03 e C ++ 11 em relação ao impacto da
std::vector
operação de inserção no validade de iteradores e referências com relação areserve()
ecapacity()
, que a resposta mais upvoted não aviso.C ++ 03:
C ++ 11:
Portanto, no C ++ 03, não é "
unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)
" como mencionado na outra resposta, mas deve ser "greater than the size specified in the most recent call to reserve()
". Isso é uma coisa que o C ++ 03 difere do C ++ 11. No C ++ 03, uma vezinsert()
que o tamanho do vetor alcance o valor especificado nareserve()
chamada anterior (que pode ser menor que a corrente,capacity()
já que areserve()
pode resultar maior docapacity()
que o solicitado), qualquer subsequenteinsert()
poderá causar realocação e invalidar todos os iteradores e referências. No C ++ 11, isso não acontecerá e você sempre pode confiarcapacity()
em saber com certeza que a próxima realocação não ocorrerá antes que o tamanho ultrapassecapacity()
.Concluindo, se você estiver trabalhando com um vetor C ++ 03 e deseja garantir que uma realocação não aconteça ao executar a inserção, é o valor do argumento que você passou anteriormente para
reserve()
o qual deve verificar o tamanho, não o valor de retorno de uma chamada paracapacity()
, caso contrário, você poderá se surpreender com uma realocação " prematura ".fonte
Aqui está uma boa tabela de resumo do cppreference.com :
Aqui, inserção refere-se a qualquer método que adiciona um ou mais elementos ao contêiner e apagamento se refere a qualquer método que remove um ou mais elementos do contêiner.
fonte