En el proceso de portación del código de C ++ a Delphi, a menudo tiene que portuar el código utilizando colecciones STL. El conjunto de colecciones ofrecidas por Delphi es muy ascética y, por lo tanto, a veces
Es difícil encontrar un reemplazo adecuado. A veces te encuentras con el código donde el objeto se coloca en la pila o usa su propio asignador de memoria.
Realmente no me gusta el modo de actualización de datos sugerido. Para actualizar los datos, necesito recuperar el valor colocado en él de la recopilación, actualizar el valor y luego volver a colocar el valor cambiado. Esto requiere al menos dos operaciones de copia adicionales. No podemos pasar un elemento de datos como parámetro VAR a un procedimiento.
No hay forma de que una colección cambie cómo se asigna la memoria. La memoria para objetos y registros se asigna a partir de un montón compartido. Después de su uso, la memoria debe devolverse cuidadosamente al montón. Librar la memoria correctamente no siempre es una tarea trivial, y se necesita tiempo del procesador y el tiempo del programador para escribir este código. En STL, puede especificar su propio asignador de memoria para todo tipo de colecciones.
Esta implementación se basa en registros y punteros. Hasta ahora, no veo ninguna forma de implementar lo que quiero usando objetos estándar. La creación y destrucción de objetos usa un montón de memoria compartido. No hay forma de colocar objetos en la pila de llamadas. El buen "objeto" antiguo se declara en desuso y agregar nuevas características para este tipo no es compatible.
Esta implementación de la colección se basa en la gestión de la memoria del mecanismo en función de las regiones de memoria tipificadas. El uso de regiones de memoria escrita permite simplificar la solución de una serie de tareas:
La tarea de liberar memoria se vuelve más fácil y se puede hacer mucho más rápido.
Es un hecho bien conocido que un administrador de memoria estándar debe ser seguro de subprocesos. Solo un hilo puede acceder al administrador de memoria en un momento dado. La asignación y la liberación de la memoria utiliza mecanismos de exclusión mutua y no es una operación rápida, especialmente si la memoria está fuertemente desfragmentada. Al usar una región de memoria escrita separada, nos referimos al administrador de memoria estándar solo al momento de aumentar la memoria requerida y eliminar la estructura después de su uso.
Soporte para estructuras básicas con la capacidad de especificar un asignador de memoria. Se accede a los elementos de la lista a través de punteros. Como regla general, la memoria para valores se encuentra en la llamada región de memoria segmentada, que no se moverá durante la operación. Si es necesario aumentar la memoria de una región, se asigna un segmento de memoria adicional. Esto significa que podemos acceder a elementos de datos ubicados en dicha región a través de un puntero.
Para las matrices, utilizamos la llamada región de memoria contigua. Se accede a los elementos de datos a través de un índice. Si es necesario, aumente la memoria de la región, se asigna un segmento con un tamaño grande y los datos del segmento de memoria actual se copian al nuevo segmento. Después de copiar los datos, se eliminará el segmento anterior.
En última instancia, trabajar a través de punteros es muy conveniente y eficiente. El código se vuelve mucho más simple y más conciso. Sin embargo, si no tiene experiencia con los consejos, es fácil "dispararse en el pie". Para los fanáticos de la encapsulación, puedes agregar la estructura deseada como un campo privado. A continuación, abrimos solo la parte necesaria de la interfaz anulando los métodos y propiedades requeridos en la sección pública. Si ponemos la opción en línea, evitamos costos adicionales. El compilador Delphi no generará código para los métodos anulados. En el lugar de la llamada del método, habrá una llamada directa al método de estructura agregada.
TsgTuple<T1, ...> tuplas genéricasTsgArray<T> Matriz genérica con asignación de memoria desde una región de memoria compartidaTsgList<T> Lista genérica de valoresTsgRecordList<T> Lista genérica de valores a los que se accede por punteroTsgLinkedList<T> Lista de vinculación bidireccional genéricaTsgForwardList<T> Lista vinculada unidireccional genéricaTsgHashMap<Key, T> Diccionario genérico desordenadoTsgMap<Key, T> Diccionario ordenado genérico basado en 2-3 árbolTsgSet<Key> Conjunto genérico basado en 2-3 árbolesTsgPointerArray Lista de punteros sin tipoTsgPointerList Lista de valores sin tipos accedidos por PointerTCustomLinkedList sin tipo bidireccional Lista vinculadaTsgCustomTree Diccionario sin tipos basado en 2-3 árboles Hemos comenzado a agregar iteradores de Delphi. Ahora podemos usar la construcción for p in List do; ¡Lo más interesante es que usamos Registro para implementar el Iterator y funciona! En comparación con el uso de objetos, el código generado es mucho más eficiente y, lo cual es bueno, no hay llamadas al montón, la variable para el iterador se encuentra en la pila. ¡Esto resultó ser una sorpresa bastante agradable para mí!
La capacidad de especificar un asignador de memoria también significa que trabajamos principalmente con registros. Por lo general, alguna estructura usa una o más regiones de memoria, que es un administrador de memoria simple. Después de usar la estructura, tenemos la oportunidad de devolver toda la memoria ocupada liberando la región de memoria. Tenemos limitaciones utilizando la herencia. En algunos casos, podemos reemplazar la herencia con agregación y ayudantes. Por lo general, para implementar colecciones, esto no es un problema. El uso de registros permite que las colecciones se apilen. Esto a veces es muy conveniente.
Un grupo de objetos le permite administrar la reutilización de estructuras al crear objetos es intensivo en la memoria o cuando se puede crear un número limitado de objetos de cierto tipo.
Si dejamos de usar algo, no siempre vale la pena eliminar la estructura u objeto. Muchas veces el objeto tiene que ser recreado.