asegurar la alineación Desafortunadamente máximo es mucho más difícil de lo que debería ser, y no existen soluciones garantizadas yo sepa. Desde el blog de GotW (Fast Pimpl article):
union max_align {
short dummy0;
long dummy1;
double dummy2;
long double dummy3;
void* dummy4;
/*...and pointers to functions, pointers to
member functions, pointers to member data,
pointers to classes, eye of newt, ...*/
};
union {
max_align m;
char x_[sizeofx];
};
Esto no se garantiza que sea totalmente portátil, pero en la práctica es lo suficientemente estrecha porque hay pocos o ningún sistemas en los que esto no funcionará como esperado.
Ese es el "hack" más cercano que conozco para esto.
Hay otro enfoque que he usado personalmente para la asignación súper rápida. Tenga en cuenta que es malo, pero trabajo en campos de trazado de rayos donde la velocidad es una de las mejores medidas de calidad y el código del perfil se realiza a diario. Implica utilizar un asignador de montón con memoria preasignada que funciona como la pila local (simplemente incrementa un puntero en la asignación y disminuye uno en la desasignación).
Lo uso especialmente para Pimpls. Sin embargo, solo tener el asignador no es suficiente; Para que funcione tal asignador, debemos suponer que la memoria para una clase, Foo, se asigna en un constructor, la misma memoria también se desasigna solo en el destructor, y que Foo mismo se crea en la pila. Para que sea seguro, necesitaba una función para ver si el puntero 'this' de una clase está en la pila local para determinar si podemos usar nuestro alocator de pila súper rápido basado en heap.Para eso tuvimos que buscar soluciones específicas del sistema operativo: utilicé TIBs y TEBs para Win32/Win64, y mis compañeros de trabajo encontraron soluciones para Linux y Mac OS X.
El resultado, después de una semana de investigación de sistemas operativos específicos métodos para detectar rango de pila, requisitos de alineación y hacer muchas pruebas y perfiles, era un asignador que podía asignar memoria en 4 ciclos de reloj de acuerdo con nuestros puntos de referencia de contador de ticks en comparación con aproximadamente 400 ciclos para malloc/operator new (nuestra prueba involucrada contención de hilo así que malloc es probable que sea un poco más rápido que esto en casos de subproceso único, quizás un par de cientos de ciclos). Agregamos un montón de subprocesos por subproceso y detectamos qué subproceso se estaba utilizando, lo que aumentó el tiempo a aproximadamente 12 ciclos, aunque el cliente puede realizar un seguimiento del asignador de subprocesos para obtener las asignaciones de 4 ciclos. Eliminó del mapa los puntos de acceso basados en asignación de memoria.
Si bien no tiene que pasar por todos esos problemas, escribir un asignador rápido podría ser más fácil y más aplicable (por ejemplo, permitir que la cantidad de memoria asignar/desasignar se determine en tiempo de ejecución) que algo como max_align
aquí. max_align
es bastante fácil de usar, pero si busca velocidad para asignaciones de memoria (y suponiendo que ya ha perfilado su código y encontrado hotspots en malloc/free/operator new/delete con los principales contribuyentes en el código que tiene control) , escribir tu propio asignador realmente puede hacer la diferencia.
portátil en lo que respecta, exactamente? para cada compilador? para cada sistema operativo? para cada arquitectura? –
Simplemente portátil como en "garantizado por el estándar C++ para trabajar". Por supuesto, podría confiar fácilmente en mi propio conocimiento de la arquitectura objetivo y codificar la alineación máxima, pero sería bueno que el lenguaje en sí proporcionara las herramientas para responder a esto. – jalf
Tenga en cuenta que el parámetro de plantilla 'Align' de' std :: aligned_storage 'tiene un argumento predeterminado de" default-alignment ", que se define como" El valor de default-alignment debe ser el requisito de alineación más estricto para cualquier objeto C++ tipo cuyo tamaño no es mayor que 'Len'." No sé si los tipos SSE se consideran "tipos de objetos C++" y la Biblioteca estándar VC10 no tiene el argumento predeterminado, por lo que no sé cuál es el valor previsto (no tengo ninguna otra biblioteca estándar) implementaciones en esta máquina). –