2011-11-02 27 views
5

Estoy intentando crear un vector agnóstico en C++ que se distingue por dos cosas. Primero, asigna la memoria en el objeto mismo, al menos hasta cierto punto, en lugar de mantener la matriz real de objetos en el montón. En segundo lugar, no puede usar los constructores de copia/asignación de C++, lo que parece ralentizar el código y no es necesario.Al mover/copiar instancias de objetos C++

Al mirar a través de la base de código que mantengo en mi computadora, encontré una clase en el código base de LLVM que describe perfectamente lo que estoy buscando: SmallVector.h. Siendo relativamente nuevo en C++, no estoy del todo seguro de por qué se tomaron algunas de las decisiones de diseño. Por ejemplo, ¿por qué la matriz se asigna en términos de U en lugar de T? El comentario da una pista:

Si T tiene un ctor o dtor, no queremos que se ejecute automáticamente, por lo que tenemos que representar el espacio como algo más. Una matriz de caracteres funcionaría muy bien, pero podría no estar lo suficientemente alineada. En su lugar, utilizamos algunas instancias de unión para el espacio, lo que garantiza la alineación máxima.

U, por supuesto, se refiere a la siguiente unión:

union U { 
    double D; 
    long double LD; 
    long long L; 
    void *P; 
} FirstEl; 

lo tanto, supongo, que aquí son mis verdaderas preguntas: ¿Por qué la asignación de una serie de T implica que los constructores/destructores se llaman? ¿Hay alguna forma de mover las instancias de objeto C++, es decir, dentro y fuera del vector, sin llamar a estos constructores/destructores? Creo que puedo usar la implementación de LLVM SmallVector, pero odio usar código sin entenderlo.

Mejor, Duane

+0

'C++ copia/asigna constructores, lo que parece ralentizar el código ...' Hace _corregir_ código, porque _son_necesarios. Hay varias clases que se bloquearán si alguna vez se vuelven a copiar, y no tienen un constructor predeterminado. –

Respuesta

3

Usted debe mirar la maquinaria básica detrás de la biblioteca estándar asignadores, que se ocupan de muchas de las preguntas que probablemente tenga!

Aquí está el principio básico de asignación. Separamos la asignación de memoria y la construcción de objetos. El gran obstáculo es, como usted observó, que la memoria debe alinearse correctamente para el objeto:

// getting memory 
void * p = malloc(1000); // version 1, system's allocator 
char q[1000];    // automatic array, this is also memory :-) 

// constructing an object 
T * m_x1 = ::new (p) T; // default-initialized 
T * m_x2 = ::new (q) T(); // value-initialized 
T * m_x3 = ::new (q + sizeof(T)) T(1, 'a'); // some specific constructor 

// destroying the objects: 
m_x1->~T(); 
m_x2->~T(); 
m_x3->~T(); 

Para hacer lo que tiene en mente, usted podría tomar la matriz de caracteres q que he usado y convertirlo en un miembro de tu claseEs decir, la clase siempre lleva consigo algo de memoria para construir objetos.

La construcción del objeto real se realiza con la colocación global-nueva expresión. Recuerde que los objetos así construidos deben destruirse manualmente (que será su responsabilidad).

Los asignadores de biblioteca estándar hacen algo así como eso.

Separar la asignación de memoria y la construcción de objetos es la base de cualquier clase de administración de memoria avanzada, clase propietaria de responsabilidad.

Tenga en cuenta que una vez que un objeto se construye en una dirección específica, no debe mover la memoria alrededor de. ¡El objeto puede muy bien depender de su propia ubicación en la memoria! La única forma válida de mover objetos es copiar/mover-construir un nuevo objeto.

1

¿Por qué asignar una matriz de T implica que los constructores/destructores se llaman?

Porque eso es lo que exige la norma. Asignar una matriz de T significa inicializar también cada uno de sus elementos. Tenga en cuenta que en C++ 11 las restricciones de alineación para char se han cambiado para que "una matriz de caracteres funcione de maravilla" ahora.

¿Hay alguna manera de mover las instancias de objeto C++, es decir, dentro y fuera del vector, sin llamar a estos constructores/destructores?

Sí, mediante move-constructors/assignment operators, que también son nuevos para C++ 11. Hay una biblioteca de emulador para C++ 03 y también contenedores de soporte de movimiento en Boost.

+1

Nota: Una _ matriz dinámicamente asignada_ de char funciona para todas las alineaciones. Una matriz automática de caracteres podría no. –

0

C++ 11 también tiene semántica de movimiento. Si implementa un constructor de movimiento en su clase (digamos Foo), std :: vector funcionará mucho mejor.

Cuestiones relacionadas