Diferencia en std:: vector:: emplace_back entre GCC y VC++
visual-c++ c++11 (1)
Cuando usaste & operator [], eso devolvió una referencia. A continuación, utilizó emplace_back que causó la reasignación y, por lo tanto, invalidó todas las referencias anteriores. Ambas reglas están bien definidas. Lo correcto que debería suceder es una excepción. De hecho, espero que la versión de VC ++ arroje una excepción si está ejecutando la versión de depuración en el depurador.
push_back tiene las mismas dos reglas, lo que significa que también hará lo mismo. Estoy casi seguro, al intercambiar las dos líneas, emplace_back / push_back dará como resultado el mismo comportamiento.
Esta pregunta ya tiene una respuesta aquí:
He escuchado que una de las recomendaciones de Modern C ++ es usar emplace_back
lugar de push_back
para anexar en contenedores ( emplace_back
acepta cualquier versión de parámetros de cualquier constructor del tipo storage en el contenedor).
De acuerdo con el borrador estándar N3797 23.3.6.5 (1) , diga que:
Observaciones: Causa la reasignación si el nuevo tamaño es mayor que la capacidad anterior. Si no se realiza una reasignación, todos los iteradores y referencias anteriores al punto de inserción permanecen válidos. Si se lanza una excepción que no sea el constructor de copia, mueva el constructor, el operador de asignación o el operador de asignación de movimiento de T o, por cualquier operación de InputIterator, no haya efectos. Si el constructor de movimientos de una T no copiada arroja una excepción, los efectos no se especifican.
Esto especifica lo que sucede cuando no se necesita una reasignación, pero deja abierto el problema cuando el contenedor necesita crecer.
En esta pieza de Código:
#include <iostream>
#include <vector>
int main() {
std::vector<unsigned char> buff {1, 2, 3, 4};
buff.emplace_back(buff[0]);
buff.push_back(buff[1]);
for (const auto& c : buff) {
std::cout << std::hex << static_cast<long>(c) << ", ";
}
std::cout << std::endl;
return 0;
}
Compilado con VC ++ (Visual Studio 2013 Update 4) y GCC 4.9.1 (MinGW) en Debug en Windows 8.1.
Cuando se compila con VC ++, la salida es:
1, 2, 3, 4, dd, 2
Cuando se compila con GCC, la salida es:
1, 2, 3, 4, 1, 2
Comprobando la implementación de emplace_back
en VC ++ la diferencia es que las primeras líneas de código, verifican si el contenedor necesita crecer (y crecer si es necesario), en el caso de que el contenedor necesite crecer, la referencia al primer elemento ( buff) [0] ) recibido en el método emplace_back
se invalida y cuando se produce la configuración real del valor en el nuevo elemento creado del contenedor, el valor no es válido.
En el caso del trabajo push_back
porque la creación del elemento para anexar se realiza en el enlace del parámetro (antes del posible crecimiento del contenedor).
Mi pregunta es: este comportamiento, cuando el contenedor necesita crecer porque una llamada a emplace_back
y el parámetro es una referencia al mismo contenedor está definida la implementación, no especificada o hay un problema en la implementación de uno de los compiladores (supongamos en VC ++ ya que el comportamiento de GCC está más cerca de lo esperado)?