principales lista librerias lenguaje funciones estandar ejemplos crear clases bibliotecas biblioteca c++ gcc c++11 mingw rvalue-reference

c++ - lista - Contenedores de biblioteca estándar que producen muchas copias en valores en GCC



lista de librerias en lenguaje c (5)

Ambas implementaciones (Visual C ++ 2010 y GCC 4.4.0) están en error. La salida correcta es:

default default default

Esto se especifica en 23.3.5.1 [vector.cons] / 4:

Requiere: T será DefaultConstructible.

La implementación no puede asumir que A sea MoveConstructible o CopyConstructible.

Estoy escribiendo una aplicación para Linux y Windows, y noté que la compilación GCC está produciendo muchas llamadas inútiles al constructor de copias.

Aquí hay un código de ejemplo para producir este comportamiento:

struct A { A() { std::cout << "default" << std::endl; } A(A&& rvalue) { std::cout << "move" << std::endl; } A(const A& lvalue) { std::cout << "copy" << std::endl; } A& operator =(A a) { std::cout << "assign" << std::endl; return *this; } }; BOOST_AUTO_TEST_CASE(test_copy_semantics) { std::vector<A> vec_a( 3 ); }

Esta prueba solo crea un vector de 3 elementos. Espero 3 llamadas de constructor predeterminadas y 0 copias ya que no hay valores de A

En Visual C ++ 2010, la salida es:

default move default move default move

En GCC 4.4.0 (MinGW), (-O2 -std = c ++ 0x), la salida es:

default copy copy copy

¿Qué está pasando y cómo lo arreglo? Las copias son caras para la clase real, la construcción predeterminada y los movimientos son baratos.


Creo que las 3 variantes no violan el borrador de C ++ 0x. Requiere lo siguiente: 1. Construye un vector con n elementos inicializados con valor 2. T será DefaultConstructible 3. Lineal en n

Las 3 variantes satisfacen 1, como predeterminado + copiar, predeterminada + mover son equivalentes a predeterminadas Las 3 variantes satisfacen 3 Las 3 variantes satisfacen 2: funcionan para los tipos DefaultConstructible. Algoritmo específico puede ser usado para tipos móviles. Es una práctica general en STL usar diferentes versiones de algoritmos para tipos con diferentes capacidades.


Intenta esto entonces:

std::vector<A> vec_a; vec_a.reserve(3); for (size_t i = 0; i < 3; ++i) vec_a.push_back(A());

Lo que estás tratando de hacer es forzar el proceso de inicialización para usar constructo + movimiento para cada valor en lugar de construir y luego copiar / copiar / copiar. Estas son solo filosofías diferentes; Los autores de las bibliotecas no podrían saber cuál será el mejor para cualquier tipo dado.


Parece que el problema es que la versión de g ++ que tiene no tiene una biblioteca totalmente compatible con C ++ 0x. En particular, en C ++ 03, el constructor de tamaño de std :: vector tiene la siguiente firma:

// C++ 03 explicit vector(size_type n, const T& value = T(), const Allocator& = Allocator());

Con esa firma de función y su llamada, se crea un temporal, luego se enlaza con la referencia constante y se crean copias de la misma para cada uno de los elementos.

Mientras que en C ++ 0x hay diferentes constructores:

// C++0x explicit vector(size_type n); vector(size_type n, const T& value, const Allocator& = Allocator());

En este caso, su llamada coincidirá con la primera firma, y ​​los elementos deben construirse de manera predeterminada con una ubicación nueva sobre el contenedor (como @Howard Hinnant señala correctamente en su answer el compilador no debe llamar al constructor de movimientos).

Puede probar y verificar si las versiones más recientes de g ++ tienen una biblioteca estándar actualizada, o puede solucionar el problema agregando manualmente los elementos:

std::vector<A> v; v.reserve( 3 ); // avoid multiple relocations while (v.size() < 3 ) v.push_back( A() );


Puede agregar un caso especial (barato) para copiar el algoritmo ctor al copiar el objeto construido predeterminado en "este" objeto. Es solo una solución, sin embargo, el comportamiento es bastante extraño. Ambos compiladores (bibliotecas) crean un objeto temporal en la pila, luego gcc copia este temporal en los objetivos 3 veces; msvc recrea el objeto temporal 3 veces (!) (también en la pila) y mueve 3 veces a los objetivos. No entiendo por qué no crean objetos directamente en su lugar.