Reglas de invalidación de iteradores para contenedores de C++
¿Cuáles son las reglas de invalidación de iteradores para contenedores de C++?
( Nota: estas preguntas y respuestas son una entrada en las preguntas frecuentes sobre C++ de Stack Overflow . La metadiscusión sobre la pregunta en sí debe publicarse en la metapregunta que inició todo esto , no aquí).C++03 (Fuente: Reglas de invalidación de iteradores (C++03) )
Inserción
Contenedores de secuencia
vector
: todos los iteradores y referencias antes del punto de inserción no se ven afectados, a menos que el nuevo tamaño del contenedor sea mayor que la capacidad anterior (en cuyo caso todos los iteradores y referencias se invalidan) [23.2.4.3/1]deque
: todos los iteradores y referencias se invalidan, a menos que el miembro insertado esté al final (anverso o reverso) de la deque (en cuyo caso se invalidan todos los iteradores, pero las referencias a elementos no se ven afectadas) [23.2.1.3/1]list
: todos los iteradores y referencias no se ven afectados [23.2.2.3/1]
Contenedores asociativos
[multi]{set,map}
: todos los iteradores y referencias no se ven afectados [23.1.2/8]
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Borradura
Contenedores de secuencia
vector
: cada iterador y referencia después del punto de borrado se invalida [23.2.4.3/3]deque
: todos los iteradores y referencias se invalidan, a menos que los miembros borrados estén al final (anverso o reverso) de la deque (en cuyo caso solo se invalidan los iteradores y las referencias a los miembros borrados) [23.2.1.3/4]list
: solo se invalidan los iteradores y las referencias al elemento borrado [23.2.2.3/3]
Contenedores asociativos
[multi]{set,map}
: sólo se invalidan los iteradores y las referencias a los elementos borrados [23.1.2/8]
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Cambiar el tamaño
vector
: según insertar/borrar [23.2.4.2/6]deque
: según insertar/borrar [23.2.1.2/1]list
: según insertar/borrar [23.2.2.2/1]
Nota 1
A menos que se especifique lo contrario (ya sea explícitamente o definiendo una función en términos de otras funciones), invocar una función miembro del contenedor o pasar un contenedor como argumento a una función de biblioteca no invalidará los iteradores ni cambiará los valores de los objetos dentro de ese contenedor. . [23.1/11]
Nota 2
No está claro en C++ 2003 si los iteradores "finales" están sujetos a las reglas anteriores ; de todos modos, debes asumir que lo son (como es el caso en la práctica).
Nota 3
Las reglas para la invalidación de punteros son las mismas que las reglas para la invalidación de referencias.
C++11 (Fuente: Reglas de invalidación de iteradores (C++0x) )
Inserción
Contenedores de secuencia
vector
: todos los iteradores y referencias antes del punto de inserción no se ven afectados, a menos que el nuevo tamaño del contenedor sea mayor que la capacidad anterior (en cuyo caso todos los iteradores y referencias se invalidan) [23.3.6.5/1]deque
: todos los iteradores y referencias se invalidan, a menos que el miembro insertado esté al final (delante o detrás) de la deque (en cuyo caso se invalidan todos los iteradores, pero las referencias a elementos no se ven afectadas) [23.3.3.4/1]list
: todos los iteradores y referencias no se ven afectados [23.3.5.4/1]forward_list
: todos los iteradores y referencias no se ven afectados (se aplica ainsert_after
) [23.3.4.5/1]array
: (n / A)
Contenedores asociativos
[multi]{set,map}
: todos los iteradores y referencias no se ven afectados [23.2.4/9]
Contenedores asociativos sin clasificar
unordered_[multi]{set,map}
: todos los iteradores se invalidan cuando se produce el refrito, pero las referencias no se ven afectadas [23.2.5/8]. La repetición no se produce si la inserción no hace que el tamaño del contenedor excedaz * B
dondez
está el factor de carga máximo yB
el número actual de cubos. [23.2.5/14]
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Borradura
Contenedores de secuencia
vector
: cada iterador y referencia en o después del punto de borrado se invalida [23.3.6.5/3]deque
: borrar el último elemento invalida sólo los iteradores y las referencias a los elementos borrados y al iterador pasado el final; borrar el primer elemento invalida sólo los iteradores y las referencias a los elementos borrados; borrar cualquier otro elemento invalida todos los iteradores y referencias (incluido el iterador pasado el final) [23.3.3.4/4]list
: solo se invalidan los iteradores y las referencias al elemento borrado [23.3.5.4/3]forward_list
: solo se invalidan los iteradores y las referencias al elemento borrado (se aplica aerase_after
) [23.3.4.5/1]array
: (n / A)
Contenedores asociativos
[multi]{set,map}
: sólo se invalidan los iteradores y las referencias a los elementos borrados [23.2.4/9]
Contenedores asociativos desordenados
unordered_[multi]{set,map}
: sólo se invalidan los iteradores y las referencias a los elementos borrados [23.2.5/13]
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Cambiar el tamaño
vector
: según insertar/borrar [23.3.6.5/12]deque
: según insertar/borrar [23.3.3.3/3]list
: según insertar/borrar [23.3.5.3/1]forward_list
: según insertar/borrar [23.3.4.5/25]array
: (n / A)
Nota 1
A menos que se especifique lo contrario (ya sea explícitamente o definiendo una función en términos de otras funciones), invocar una función miembro del contenedor o pasar un contenedor como argumento a una función de biblioteca no invalidará los iteradores ni cambiará los valores de los objetos dentro de ese contenedor. . [23.2.1/11]
Nota 2
ninguna función swap() invalida cualquier referencia, puntero o iterador que haga referencia a los elementos de los contenedores que se intercambian. [Nota: el iterador end() no hace referencia a ningún elemento, por lo que puede invalidarse . —nota final] [23.2.1/10]
Nota 3
Aparte de la advertencia anterior con respecto a swap()
, no está claro si los iteradores "finales" están sujetos a las reglas por contenedor enumeradas anteriormente ; debes asumir, de todos modos, que lo son.
Nota 4
vector
y soporte para todos los contenedores asociativos desordenadosreserve(n)
, lo que garantiza que no se producirá ningún cambio de tamaño automático al menos hasta que el tamaño del contenedor crezca hasta n
. Se debe tener precaución con los contenedores asociativos desordenados porque una propuesta futura permitirá la especificación de un factor de carga mínimo, lo que permitiría que se produzca una repetición insert
después de que suficientes erase
operaciones reduzcan el tamaño del contenedor por debajo del mínimo; la garantía debe considerarse potencialmente nula después de un erase
.
C++17 (Todas las referencias son del borrador final de trabajo de CPP17 - n4659 )
Inserción
Contenedores de secuencia
vector
: Las funcionesinsert
,emplace_back
,emplace
,push_back
provocan una reasignación si el nuevo tamaño es mayor que la capacidad anterior. La reasignación invalida todas las referencias, punteros e iteradores que hacen referencia a los elementos de la secuencia. Si no se produce ninguna reasignación, todos los iteradores y referencias antes del punto de inserción siguen siendo válidos. [26.3.11.5/1]
Con respecto a lareserve
función, la reasignación invalida todas las referencias, punteros e iteradores que hacen referencia a los elementos de la secuencia. No se realizará ninguna reasignación durante las inserciones que ocurren después de una llamada areserve()
hasta el momento en que una inserción haga que el tamaño del vector sea mayor que el valor decapacity()
. [26.3.11.3/6]deque
: Una inserción en medio del deque invalida todos los iteradores y referencias a elementos del deque. Una inserción en cualquier extremo del deque invalida todos los iteradores del deque, pero no tiene ningún efecto sobre la validez de las referencias a elementos del deque. [26.3.8.4/1]list
: No afecta la validez de iteradores y referencias. Si se lanza una excepción, no hay efectos. [26.3.10.4/1].
Las funcionesinsert
,emplace_front
,emplace_back
,emplace
,push_front
,push_back
están cubiertas por esta regla.forward_list
: Ninguna de las sobrecargasinsert_after
afectará la validez de los iteradores y las referencias [26.3.9.5/1]array
: Como regla general , los iteradores de una matriz nunca se invalidan durante la vida útil de la matriz. Sin embargo, hay que tener en cuenta que durante el intercambio, el iterador seguirá apuntando al mismo elemento de la matriz y, por tanto, cambiará su valor.
Contenedores asociativos
All Associative Containers
: Los miembrosinsert
yemplace
no afectarán la validez de los iteradores y las referencias al contenedor [26.2.6/9]
Contenedores asociativos desordenados
All Unordered Associative Containers
: La repetición invalida los iteradores, cambia el orden entre los elementos y cambia en qué depósitos aparecen los elementos, pero no invalida los punteros ni las referencias a los elementos. [26.2.7/9]
Los miembrosinsert
andemplace
no afectarán la validez de las referencias a elementos del contenedor, pero pueden invalidar todos los iteradores del contenedor. [26.2.7/14]
Los miembrosinsert
andemplace
no afectarán la validez de los iteradores si(N+n) <= z * B
, dondeN
es el número de elementos en el contenedor antes de la operación de inserción,n
es el número de elementos insertados,B
es el recuento de depósitos del contenedor yz
es el factor de carga máximo del contenedor. [26.2.7/15]All Unordered Associative Containers
: En caso de una operación de fusión (por ejemplo,a.merge(a2)
), los iteradores que hacen referencia a los elementos transferidos y todos los iteradores que hacen referencia aa
se invalidarán, pero los iteradores a los elementos que permanecena2
seguirán siendo válidos. (Tabla 91: requisitos de contenedores asociativos desordenados)
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Borradura
Contenedores de secuencia
vector
: Las funcioneserase
epop_back
invalidan iteradores y referencias en o después del punto de borrado. [26.3.11.5/3]deque
: Una operación de borrado que borra el último elemento de adeque
invalida solo el iterador pasado el final y todos los iteradores y referencias a los elementos borrados. Una operación de borrado que borra el primer elemento de un elemento,deque
pero no el último, invalida sólo los iteradores y las referencias a los elementos borrados. Una operación de borrado que no borra ni el primer elemento ni el último elemento de adeque
invalida el iterador pasado el final y todos los iteradores y referencias a todos los elementos dedeque
. [Nota:pop_front
ypop_back
son operaciones de borrado. —nota final] [26.3.8.4/4]list
: Invalida solo los iteradores y las referencias a los elementos borrados. [26.3.10.4/3]. Esto se aplica a las funcioneserase
,pop_front
,pop_back
. y funciones miembro: Borra todos los elementos de la lista a los que hace referencia un iterador de lista para el cual se cumplen las siguientes condiciones: , . Invalida solo los iteradores y las referencias a los elementos borrados [26.3.10.5/15]. Función miembro: borra todos menos el primer elemento de cada grupo consecutivo de elementos iguales a los que hace referencia el iterador en el rango para el cual (para la versión de único sin argumentos) o (para la versión de único con un argumento de predicado) se cumple. Invalida solo los iteradores y las referencias a los elementos borrados. [26.3.10.5/19]clear
remove
remove_if
i
*i == value
pred(*i) != false
unique
i
[first + 1, last)
*i == *(i-1)
pred(*i, *(i - 1))
forward_list
:erase_after
invalidará solo los iteradores y las referencias a los elementos borrados. [26.3.9.5/1].
remove
yremove_if
funciones miembro: borra todos los elementos de la lista a los que hace referencia un iterador de lista i para los cuales se cumplen las siguientes condiciones:*i == value
(pararemove()
),pred(*i)
es verdadero (pararemove_if()
). Invalida solo los iteradores y las referencias a los elementos borrados. [26.3.9.6/12].
unique
Función miembro: borra todos menos el primer elemento de cada grupo consecutivo de elementos iguales a los que hace referencia el iterador i en el rango [primero + 1, último) para el cual*i == *(i-1)
(para la versión sin argumentos) opred(*i, *(i - 1))
(para la versión con un predicado argumento) se cumple. Invalida solo los iteradores y las referencias a los elementos borrados. [26.3.9.6/16]All Sequence Containers
:clear
invalida todas las referencias, punteros e iteradores que hacen referencia a los elementos de a y puede invalidar el iterador pasado el final (Tabla 87 — Requisitos del contenedor de secuencia). Pero paraforward_list
,clear
no invalida los iteradores pasados el final. [26.3.9.5/32]All Sequence Containers
:assign
invalida todas las referencias, punteros e iteradores que hacen referencia a los elementos del contenedor. Forvector
ydeque
, también invalida el iterador pasado el final. (Tabla 87 — Requisitos del contenedor de secuencias)
Contenedores asociativos
All Associative Containers
: Loserase
miembros invalidarán sólo los iteradores y las referencias a los elementos borrados [26.2.6/9]All Associative Containers
: Losextract
miembros invalidan sólo los iteradores del elemento eliminado; los punteros y las referencias al elemento eliminado siguen siendo válidos [26.2.6/10]
Adaptadores de contenedores
stack
: heredado del contenedor subyacentequeue
: heredado del contenedor subyacentepriority_queue
: heredado del contenedor subyacente
Requisitos generales del contenedor relacionados con la invalidación del iterador:
A menos que se especifique lo contrario (ya sea explícitamente o definiendo una función en términos de otras funciones), invocar una función miembro del contenedor o pasar un contenedor como argumento a una función de biblioteca no invalidará los iteradores ni cambiará los valores de los objetos dentro de ese contenedor. . [26.2.1/12]
ninguna
swap()
función invalida las referencias, punteros o iteradores que hagan referencia a los elementos de los contenedores que se intercambian. [Nota: El iterador end() no hace referencia a ningún elemento, por lo que puede invalidarse. —nota final] [26.2.1/(11.6)]
Como ejemplos de los requisitos anteriores:
transform
algoritmo: Las funcionesop
ybinary_op
no invalidarán iteradores o subrangos, ni modificarán elementos en los rangos [28.6.4/1]accumulate
algoritmo: En el rango [primero, último],binary_op
no modificará elementos ni invalidará iteradores o subrangos [29.8.2/1]reduce
algoritmo: binario_op no invalidará iteradores o subrangos, ni modificará elementos en el rango [primero, último]. [29.8.3/5]
etcétera...