Estructura de datos sencilla

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 20 de noviembre de 2013; las comprobaciones requieren 58 ediciones .

Una estructura de datos simple ( eng.  Plain Old Data , POD ) es un tipo de datos en lenguajes de programación modernos de alto nivel que tiene una disposición rígidamente definida de campos en la memoria que no requiere restricciones de acceso y control automático . Las variables de este tipo se pueden copiar con rutinas simples de copia de memoria como . Lo contrario es una estructura de datos administrados . memcpy

La forma más fácil de definir una estructura de datos simple es por contradicción. Si el compilador reorganiza en secreto los campos del usuario, o al crear una estructura de datos, llama en secreto al constructor , o llama al destructor cuando se destruye la estructura , o al copiar, un procedimiento de copia especial, entonces esto es administrado (es decir , no simple) estructura.

Beneficios de las estructuras de datos simples

Las estructuras de datos simples tienen dos características.

Dispositivo predecible en la memoria

El compilador puede reconstruir automáticamente la estructura de datos a su discreción (por ejemplo, cambiar el orden de los campos). En el lenguaje C++, esto solo es posible si hay una etiqueta de acceso público/privado/protegido entre los campos. Una secuencia de campos no separados por tal etiqueta deben ser colocados en la memoria en orden de declaración de campo). Tal reestructuración puede ahorrar memoria seriamente, pero rompe la compatibilidad. En los POD, esta optimización está deshabilitada.

En otras palabras: los tipos marcados como POD se organizan en la memoria exactamente como los describió el programador (quizás con alguna alineación ). Por lo tanto, solo se pueden usar POD para comunicarse entre dos bibliotecas de tiempo de ejecución . En particular, para transferir datos de un programa a otro, de un complemento a otro, para comunicarse con código escrito en otro lenguaje de programación . Para escribir rápidamente un encabezado de archivo complejo como BMP en el disco , puede formarlo en la memoria y luego escribirlo con un comando, pero la estructura de datos en la que formamos el encabezado también debe ser un POD.

Sin código de control

Esto significa que cuando aparece un objeto, no es necesario llamar al constructor, al copiar, a la operación de asignación, y al destruir, al destructor. Esto, a su vez, proporciona los siguientes beneficios:

  1. Inicialización estática. En lugar de llamar al constructor oculto del programador al iniciar el programa , los POD se pueden ensamblar mientras se compila el programa.
  2. Copia trivial (incluida la copia de matrices) mediante funciones como memcpy.
  3. Una vez más, esto es importante para la comunicación entre programas: después de todo , el administrador de memoria no debe administrar la memoria que no le pertenece.
  4. Solo los tipos simples pueden estar en union(en Pascal, respectivamente record/case).
  5. Las funciones con efectos secundarios (como las funciones del sistema que afectan el resultado de una llamada posterior GetLastError[1] ) son poco compatibles con los tipos administrados automáticamente.

Idiomas en los que todos los tipos son simples

En C++

En C++ , POD se define por contradicción. Un tipo de datos es un POD si:

De acuerdo con el estándar C++, un tipo de datos simple se estructura exactamente como se describe (y es totalmente compatible byte a byte en el diseño de memoria con una estructura C). El compilador puede reorganizar la estructura administrada de la forma que considere más eficiente.

Definición de POD anterior a C++ 11:

Un agregado es una matriz o una clase que no tiene:

Un agregado se puede inicializar (como en C) con una lista de la forma = {1, 2, 3};

El escalar se llama:

(es decir, un tipo que no es una clase, matriz o referencia)

Un POD es un escalar , o una matriz de otros POD, o una clase que es un agregado, y además:

En C++11

"Dispositivo predecible en la memoria" y "sin código de control" son propiedades de tipo similares pero diferentes. Por ejemplo, la estructura de datos STRRET[ 2] , que en Windows se usa para pasar cadenas de un administrador de memoria a otro, puede " envolverse " en el código de control, pero la segunda propiedad, el dispositivo predecible, permanece. Por lo tanto, el concepto de PODs en C++11 se divide en tres.

Una clase se llama "tener un constructor de copia trivial" si todo lo siguiente es cierto:

El constructor de copia trivial generado automáticamente es memmove().

Los términos "tener un constructor/operador de asignación/constructor de movimiento/operador de movimiento predeterminado trivial" se definen exactamente de la misma manera.

Se dice que una clase "tiene un destructor trivial" si todo lo siguiente es cierto:

Dicha clase no requiere destrucción, y la memoria que la contiene se puede desasignar sin limpiarla.

Se dice que una clase es "trivialmente copiable" si todas las funciones miembro especiales anteriores son triviales (excepto el constructor predeterminado, que puede no ser trivial). Los escalares, así como las matrices de objetos copiables trivialmente, también son copiables trivialmente. Dichos tipos se pueden copiar a través de memcpy.

Una clase se llama "trivial" si se puede copiar de forma trivial y también tiene un constructor predeterminado trivial.

En otras palabras, una clase es trivial si tiene trivial:

Una clase es un tipo de dispositivo estándar si:

Aclaremos la última condición: en el lenguaje no puede haber dos objetos diferentes del mismo tipo con la misma dirección, lo que significa que el tamaño de una clase vacía (sin campos no estáticos) no puede ser 0 (al menos 1). Sin embargo, se hace una excepción para la "parte B en la clase D: B" y su tamaño (si está vacío) puede ser estrictamente cero, lo que da como resultado que no haya "relleno" entre el comienzo de D y su primer campo. Pero al mismo tiempo, si el tipo del primer campo también es B, la excepción no se puede aplicar, porque (B *) & d y & (d. campo1) apuntan a objetos diferentes del mismo tipo, y por lo tanto el " se necesita relleno". La última condición de la lista anterior significa nada más que "en las clases de un dispositivo estándar, dicha junta está prohibida".

Dichos tipos tienen un dispositivo predecible en la memoria (por ejemplo, la dirección de un objeto como un todo es la misma que la dirección de su primer campo, naturalmente, después de reinterpret_cast al mismo tipo, por ejemplo, para anular *), pueden ser pasado a otra biblioteca en tiempo de ejecución y a otros lenguajes de programación.

Entonces POD  es una matriz de otros POD, o un escalar, o una clase trivial con un dispositivo estándar, cuyos campos no estáticos también son POD.

Para trabajar con constantes de tiempo de compilación e inicialización estática, C++ 11 tiene un concepto más suave: un tipo literal . A saber:

PODs e inicialización "predeterminada" y "valor"

Desde C++03, existe una diferencia entre T t; y T t();, así como entre la nueva T y la nueva T().

La versión con paréntesis vacíos se llama "inicialización de valor", y sin ellos se llama "inicialización predeterminada".

Inicialización predeterminada: si el constructor predeterminado es trivial, entonces no se hace nada, la basura permanece en el objeto. Si el constructor predeterminado no es trivial, entonces se ejecuta.

Inicialización por valor: si hay un constructor predeterminado escrito explícitamente, entonces se ejecuta. De lo contrario (es decir, si el constructor predeterminado es trivial o se genera automáticamente), primero se anula el objeto y solo entonces se ejecuta el constructor (si no es trivial). Los tipos escalares se establecen en cero cuando se inicializan con un valor.

Embarcadero Delfos

Todos los tipos se consideran estructuras de datos simples excepto:

Notas

  1. GetLastError Archivado el 6 de diciembre de 2013 en Wayback Machine en MSDN
  2. Estructura STRRET (Windows) . Consultado el 6 de abril de 2013. Archivado desde el original el 18 de abril de 2013.

Véase también