vectores - vector vector c++
¿Se permite insertar un elemento de un std:: vector en el mismo vector? (1)
Para responder primero a la segunda pregunta: el estándar dice explícitamente que se permite que la biblioteca estándar suponga que al pasar algo por referencia de rvalue, esa referencia de rvalue es la única referencia a ese objeto. Esto significa que legalmente no puede ser un elemento del vector. La parte relevante de C ++ 11 17.6.4.9/1:
- Si un argumento de función se enlaza con un parámetro de referencia rvalue, la implementación puede asumir que este parámetro es una referencia única a este argumento. ... [ Nota: si un programa convierte un lvalue en un xvalue mientras pasa ese lvalue a una función de la biblioteca (p. Ej., Llamando a la función con el argumento
move(x)
), el programa está solicitando esa función para tratar ese lvalue como un temporal. La implementación es libre de optimizar las comprobaciones de alias que puedan ser necesarias si el argumento fuera un valor l. "Nota final "
Esto nos deja solo para manejar la const T &
case. Y aunque libstdc ++ y libc ++ difieren en este caso, su resultado neto es el mismo: se copiarán correctamente del objeto pasado. Y el estándar solo prescribe el comportamiento, no la implementación. Mientras logren el comportamiento correcto, están bien.
Considere las siguientes funciones de insert
y emplace
miembros de std::vector<T>
:
template <class... Args> iterator emplace(const_iterator position, Args&&... args);
iterator insert(const_iterator position, const T& x);
iterator insert(const_iterator position, T&& x);
iterator insert(const_iterator position, size_type n, const T& x);
¿Qué sucede si uno de ellos se invoca con una referencia a un elemento del vector como argumento? Normalmente, cada uno de ellos invalida las referencias a todos los elementos que comienzan desde la position
, lo que podría incluir el argumento, o si ocurre una reasignación, las referencias a todos los elementos, que definitivamente lo incluyen, pero esto significa que dicha invocación no es válida o hace la inserción ( parece que sucede primero?
Mirar algunas implementaciones comunes da resultados curiosos:
libstdc ++ copia el argumento antes de mover cualquier elemento, pero solo en las
const T&
sobrecargas deinsert
. Contiene este comentario:El orden de las tres operaciones es dictado por el caso C ++ 0x, donde los movimientos podrían alterar un nuevo elemento que pertenece al vector existente. Este es un problema solo para quienes llaman y toman el elemento por const lvalue ref (ver 23.1 / 13).
Pero C ++ 11 §23.1 es solo un breve resumen de la biblioteca de contenedores, e incluso si asumimos que esto se refiere a §23.2.1 (que solía ser §23.1 en C ++ 03), §23.2.1 / 13 solamente da una definición de contenedores conscientes de los asignadores, que parece no tener nada que ver con esto. He revisado el capítulo 23, pero no he encontrado nada relevante en ninguna parte.
libc ++ crea un temporal antes de mover cualquier elemento en
emplace
, mientras que eninsert
mueve primero los elementos, pero convierte la referencia del argumento en un puntero y lo ajusta para asegurarse de que apunta al elemento original, pero nuevamente, hace todo esto solo en laconst T&
sobrecarga.Visual C ++ crea una copia / temporal antes de mover cualquier elemento en todos los casos.
¿Extrañé el lugar donde el estándar define este comportamiento? ¿Por qué las tres bibliotecas de C ++ que miré están en desacuerdo entre sí? ¿Por qué el comentario de libstdc ++ dice que solo es un problema para insert(const_iterator, const T&)
? Si el estándar no requiere que esto funcione, ¿por qué las bibliotecas se molestan en hacerlo funcionar? (Seguramente esto cuesta algunas copias y / o movimientos que de otra manera podrían evitarse). Finalmente, si estoy implementando un contenedor que debería parecerse a std::vector
, ¿debería hacer este trabajo?