Resultados incorrectos cuando se agrega el vector a sí mismo usando copy y back_inserter

Inspirado por esta pregunta , preguntando cómo agregarse un vector a sí mismo, mi primer pensamiento fue el siguiente (y sí, me doy cuenta de que insert es una mejor opción):

 #include  #include  #include  #include  int main() { std::vector vec {1, 2, 3}; std::copy (std::begin (vec), std::end (vec), std::back_inserter (vec)); for (const auto &v : vec) std::cout << v << ' '; } 

Sin embargo, esto imprime:

 1 2 3 1 * 3 

El * es un número diferente cada vez que se ejecuta el progtwig. El hecho de que solo se reemplacen los 2 es peculiar, y si realmente hay una explicación para eso, me interesaría escucharlo. Continuando, si agrego a un vector diferente (una copia del original), se imprime correctamente. También sale correctamente si agrego la siguiente línea antes de la copy :

 vec.reserve (2 * vec.size()); 

Tenía la impresión de que std::back_inserter era una forma segura de agregar elementos al final de un contenedor, a pesar de no reservar memoria de antemano. Si mi entendimiento es correcto, ¿qué hay de malo con la línea de copia?

Supongo que no tiene nada que ver con el comstackdor, pero estoy usando GCC 4.7.1.

std::back_inserter crea un iterador de inserción que inserta elementos en un contenedor. Cada vez que se elimina la referencia a este iterador, llama a push_back en el contenedor para agregar un nuevo elemento al contenedor.

Para un contenedor std::vector , una llamada a push_back donde v.size() == v.capacity() resultará en una reasignación : se crea una nueva matriz para almacenar el contenido del vector, su contenido actual se copia en la nueva matriz, y la antigua matriz se destruye. Cualquier iterador en el vector en este momento se invalida , lo que significa que ya no se pueden usar.

En su progtwig, esto incluye el rango de entrada definido por begin(vec) y end(vec) desde el cual se copy algoritmo de copia. El algoritmo continúa utilizando estos iteradores, aunque estén invalidados, por lo que su progtwig muestra un comportamiento indefinido.


Incluso si su contenedor tuviera suficiente capacidad, su comportamiento aún sería indefinido: la especificación establece que, al insertarse, “si no se realiza una reasignación, todos los iteradores y las referencias anteriores al punto de inserción siguen siendo válidos” (C ++ 11 §23.3.6.5 / 1).

La llamada a push_back es equivalente a la inserción al final, por lo que el iterador final ( std::end(vec) ) que push_back en std::copy se invalida después de una sola llamada a push_back . Si el rango de entrada no es vacío, el progtwig exhibe un comportamiento indefinido.


Tenga en cuenta que el comportamiento de su progtwig estaría bien definido si usara un std::deque o un std::list , porque ninguno de esos contenedores invalida los iteradores cuando se agregan elementos.