2010-10-24 11 views
5

¿Cómo se implementa el vector STL? Tiene un almacenamiento en bruto de char [] que de vez en cuando cambia de tamaño por cierto factor y luego llama a la ubicación nueva cuando un elemento es push_back (una forma gramatical muy interesante que debería notar; los lingüistas deberían estudiar tales formas verbales como push_back :)
Y luego están los requisitos de alineación. Entonces surge la pregunta natural de cómo puedo llamar a una ubicación nueva en un char [] y asegurarme de que se satisfacen los requisitos de alineación. Así que busqué estándar de C++ de 2003 por la palabra "alineación" y encontrado los:Alineación de matrices de caracteres

Párrafo 3.9 Cláusula 5

tipos de objetos tienen requisitos de alineación (3.9.1, 3.9.2). La alineación de un tipo de objeto completo es un valor entero definido por la implementación que representa un número de bytes; un objeto se asigna a una dirección que cumple los requisitos de alineación de su tipo de objeto.

Párrafo 5.3.4 Cláusula 10:

Una nueva expresión pasa a la cantidad de espacio requerido para la función de asignación como el primer argumento de tipo std :: size_t. Ese argumento no será menor que el tamaño del objeto que se está creando; puede ser mayor que el tamaño del objeto que se crea solo si el objeto es una matriz. Para matrices de char y char sin signo, la diferencia entre el resultado de la nueva expresión y la dirección devuelta por la función de asignación será un múltiplo entero del requisito de alineación más estricto (3.9) de cualquier tipo de objeto cuyo tamaño no sea mayor que el tamaño de la matriz que se está creando [Nota: dado que se supone que las funciones de asignación devuelven los punteros al almacenamiento alineado adecuadamente para objetos de cualquier tipo, esta restricción en la tara de asignación de matrices permite la expresión común de la asignación de matrices de caracteres en las que posteriormente se colocarán objetos de otros tipos. ]

Estos dos dan una respuesta muy satisfactoria para mi pregunta anterior, pero ...

Sentencia1:
Un requisito de alineación para un objeto de tipo X en sizeof (X) == n es al menos el requisito de que la dirección de X sea divisible por n o algo así (ponga todas las cosas dependientes de la arquitectura en "o algo así").

Pregunta 1: Por favor confirmar, refinar, o negar la sentencia1 anteriormente.

Statement2: Si statement1 es correcto, a partir de la segunda cita en el estándar se deduce que una matriz de 5000000 caracteres se asigna a una dirección divisible por 5000000 que es completamente innecesaria si solo necesito el conjunto de caracteres como tal, no como almacenamiento en bruto para la posible ubicación de otros objetos.

Pregunta 2: Por lo tanto, son las posibilidades de éxito la asignación de 1000 caracteres realmente menor de 500 cortos (siempre corta es de 2 bytes)? ¿Es prácticamente un problema?

Respuesta

3

Un requisito de alineación para un objeto de tipo X donde sizeof (X) == n es al menos el requisito de que la dirección de X sea divisible por n o algo así que

No. El requisito de alineación de un tipo siempre es un factor de su tamaño, pero no tiene por qué ser igual a su tamaño. Por lo general, es igual al mayor de los requisitos de alineación de todos los miembros de una clase.

Una matriz de 5M de caracteres, por su propia cuenta, solo necesita tener un requisito de alineación de 1, el mismo que el requisito de alineación de un solo char.

Así, el texto que cita sobre la alineación de memoria asignada a través de operador global new, (y malloc tiene una similar, aunque IIRC no prescripción idéntica), en efecto, significa que una gran asignación debe obedecer a los más estrictos requisitos de alineación de cualquier tipo en el sistema. Además de eso, las implementaciones a menudo excluyen los tipos de SIMD grandes de esto, y requieren que la memoria para SIMD se asigne especialmente. Esto es un poco dudoso, pero creo que lo justifican sobre la base de que los tipos de extensión no estándar pueden imponer requisitos especiales arbitrarios.

Así que en la práctica el número que usted piensa que es 5000000 es a menudo :-) 4

1

Q1: La alineación no está relacionada con el tamaño.

Q2: Teóricamente sí, pero difícilmente encontrará una arquitectura que tenga un tipo con una alineación tan grande. SSE requiere una alineación de 16 bytes (la más grande que he visto).

+0

@Let_Me_Be: La razón por la que se supone la alineación ** ** está relacionado con el tamaño es que si tomo una serie de X y de todos ellos deben obedecer los requisitos de alineación, luego las direcciones a, a + sizeof (X), a + 2 * sizeof (X) ... etc. deben cumplir todos estos requisitos. Lo que me llevó a definir la declaración. ¿Me equivoco? –

+0

@Armen: lo tienes al revés. El tamaño del objeto tiene que ser un múltiplo de su alineación. Un 'char' por lo general tiene la alineación 1, y un' int' por lo general tiene que estar alineado en un límite de 4 bytes. Una 'struct' que contiene ambos se le da la alineación de su miembro más estrictamente alineado (por lo tanto, si contiene un' char' y un 'int', entonces la estructura como un todo requiere la misma alineación que un' int'). El objeto también debe tener un tamaño que sea un múltiplo de un int. Lo mismo es cierto para su gran matriz de caracteres. No contiene nada más que caracteres, y cada carácter se puede colocar en cualquier byte (cualquier dirección divisible por 1) – jalf

+0

por lo que el conjunto tiene el mismo requisito de alineación (y también tiene que ser un múltiplo de 1, lo cual no es difícil para lograrlo;;)) – jalf

4

Al asignar dinámicamente memoria utilizando operator new, tiene la garantía de que:

El puntero devuelto estarán adecuadamente alineados de manera que se puede convertir en un puntero de cualquier tipo de objeto completa y luego utilizado para acceder el objeto o matriz en el almacenamiento asignado (hasta que el almacenamiento sea explícitamente desasignado por una llamada a una función de desasignación correspondiente) (C++ 03 3.7.3.1/2).

vector no crea una matriz de caracteres; usa un asignador. El asignador predeterminado usa ::operator new para asignar memoria.