c++ - tag - std:: comportamiento anticipado al avanzar más allá del final del contenedor
instalar google tag manager (5)
Esta pregunta ya tiene una respuesta aquí:
¿Cuál es el comportamiento de std :: advance cuando ha dicho:
std::vector<int> foo(10,10);
auto i = foo.begin();
std::advance(i, 20);
¿Cuál es el valor de i ? ¿Es foo.end () ?
De acuerdo con el estándar de C ++ §24.3.4 std::advance(i, 20)
tiene el mismo efecto que for ( int n=0; n < 20; ++n ) ++i;
para n
positivo Desde el otro lado (§24.1.3) si i
está pasado el final, entonces la operación ++i
no está definida. Entonces el resultado de std::advance(i, 20)
no está definido.
Desde la página de SGI para std::advance :
Cada iterador entre i y i + n (inclusive) es no singular.
Por lo tanto, i no es foo.end () y la desreferenciación dará como resultado un comportamiento indefinido.
Notas:
- Consulte esta pregunta para obtener más detalles sobre lo que significa (no) singular al referirse a los iteradores.
- Sé que la página de SGI no es el estándar de facto, pero prácticamente todas las implementaciones de STL siguen estas pautas.
El estándar define std::advance()
en términos de los tipos de iteradores en los que se está utilizando (24.3.4 "Operaciones de iterador"):
Estas plantillas de función utilizan + y - para los iteradores de acceso aleatorio (y, por lo tanto, son un tiempo constante para ellos); para los iteradores de entrada, hacia adelante y bidireccionales que usan ++ para proporcionar implementaciones de tiempo lineal.
Los requisitos para estas operaciones en varios tipos de iteradores también se describen en la norma (en las Tablas 72, 74, 75 y 76):
Para un iterador de entrada o reenvío
++r precondition: r is dereferenceable
para un iterador bidireccional:
--r precondition: there exists s such that r == ++s
Para los iteradores de acceso aleatorio, las operaciones
+
,+=
,-
y-=
se definen en términos del prefijo iterador bidireccional y directo++
y--
operaciones, por lo que se mantienen las mismas condiciones previas.
Así que avanza un iterador más allá del valor ''pasado el fin'' (como podría ser devuelto por la función end()
en los contenedores) o avanza antes del primer elemento no referenciable del rango válido de un iterador (como podría ser devuelto por begin()
en un contenedor) es un comportamiento indefinido ya que está violando las condiciones previas de la operación ++
o --
.
Como es un comportamiento indefinido, no puedes "esperar" nada en particular. Pero es probable que se bloquee en algún momento (con suerte más temprano que tarde, para que pueda corregir el error).
Eso es probablemente un comportamiento indefinido. Lo único que dice la norma es:
Dado que solo los iteradores de acceso aleatorio proporcionan operadores + y -, la biblioteca proporciona dos plantillas de función de avance y distancia. Estas plantillas de función utilizan + y - para los iteradores de acceso aleatorio (y, por lo tanto, son un tiempo constante para ellos); para los iteradores de entrada, hacia adelante y bidireccionales que usan ++ para proporcionar implementaciones de tiempo lineal.
template <class InputIterator, class Distance>
void advance(InputIterator& i, Distance n);
Requiere: n será negativo solo para iteradores de acceso aleatorio y bidireccional. Efectos: Incrementa (o disminuye para n negativo) la referencia i del iterador por n.
Estás pasando el tamaño foo
avanzando a la posición 20. Definitivamente no es el final del vector. Debe invocar un comportamiento indefinido en la desreferenciación, AFAIK.
Edición 1:
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> foo(10,10) ;
std::vector<int>::iterator iter = foo.begin() ;
std::advance(iter,20);
std::cout << *iter << "/n" ;
return 0;
}
Salida: 0
Si es el último elemento del vector, entonces debería haber dado 10 en la desreferenciación del iterador. Entonces, es UB.