dynarray.h

Clase wxArray

template<typename T>
class wxArray< T >

La clase de arrays dinámicos heredada, existente solo por compatibilidad y que NO debe utilizarse en el nuevo código.

Esta sección describe los llamados "arrays dinámicos". Se trata de una estructura de datos segura de tipo array similar a C, es decir, el tiempo de acceso a los miembros es constante (y no lineal en función del número de elementos contenedores como en el caso de las listas enlazadas). Sin embargo, estas matrices son dinámicas en el sentido de que asignan automáticamente más memoria si no hay suficiente para añadir un nuevo elemento. También realizan la comprobación de rangos en los valores índice, pero solo en modo depuración, así que hay que asegurarse de compilar la aplicación en modo depuración para utilizarlo (ver Depuración para más detalles). Así que, a diferencia de los arrays en otros lenguajes, intentar acceder a un elemento más allá de los límites del array no expande automáticamente el array, sino que provoca un fallo de aserción en la compilación de depuración y no hace nada (excepto posiblemente bloquear tu programa) en la compilación de lanzamiento.

Las clases array se diseñaron para ser razonablemente eficientes, tanto en términos de velocidad de ejecución y consumo de memoria como de tamaño del ejecutable. La velocidad de acceso a los elementos de las matrices es, por supuesto, constante (independiente del número de elementos), lo que las hace mucho más eficientes que las listas enlazadas (wxList). La adición de elementos a las matrices también se implementa en tiempo más o menos constante, pero el precio es preasignar la memoria de antemano. En la sección de funciones "gestión de memoria", se pueden encontrar algunos consejos útiles sobre la optimización del uso de memoria de wxArray. En cuanto al tamaño del ejecutable, todas las funciones de wxArray son inline, por lo que no ocupan nada de espacio.

wxWidgets tiene tres clases diferentes de array. Todas ellas derivan de la clase wxBaseArray, que trabaja con datos no tipados y no puede utilizarse directamente. Las macros estándar WX_DEFINE_ARRAY(), WX_DEFINE_SORTED_ARRAY() y WX_DEFINE_OBJARRAY() se utilizan para definir una nueva clase que derive de ella. Las clases declaradas se llamarán en esta documentación wxArray, wxSortedArray y wxObjArray pero se debe tener en cuenta que en realidad no existen clases con esos nombres, cada vez que se utiliza una de las macros WX_DEFINE_XXXARRAY(), se define una clase con un nuevo nombre. De hecho, estos nombres son nombres de "plantilla" y cada uso de una de las macros mencionadas anteriormente crea una especialización de plantilla para el tipo de elemento dado.

wxArray es adecuado para almacenar tipos enteros y punteros a los que no trata como objetos de ninguna manera, es decir, el elemento apuntado por el puntero no se borra cuando el elemento se elimina del array. Hay que tener en cuenta que todas las funciones de wxArray son inline, por lo que no cuesta estrictamente nada definir tantos tipos de array como se quiera (ya sea en términos de tamaño ejecutable o de velocidad) siempre y cuando se defina al menos uno de ellos y esto siempre es así porque wxArrays es utilizado por wxWidgets internamente. Esta clase tiene una seria limitación: solo puede usarse para almacenar tipos enteros (bool, char, short, int, long y sus variantes sin signo) o punteros (de cualquier tipo). Un intento de uso con objetos de sizeof() mayor que sizeof(long) provocará un fallo de aserción en tiempo de ejecución, sin embargo declarar un wxArray de floats no lo hará (en las máquinas donde "sizeof(float) <= sizeof(long)"), sin embargo no funcionará, por favor utilizar wxObjArray para almacenar float y doubles.

wxSortedArray es una variante de wxArray que debe utilizarse cuando la búsqueda en el array es una operación de uso frecuente. Requiere definir una función adicional para comparar dos elementos del tipo array y siempre almacena sus elementos en orden (según esta función). Así, el tiempo de ejecución de su función Index() es "O(log(N))" en lugar de "O(N)" para las matrices habituales, pero el método Add() es más lento: es "O(log(N))" en lugar de un tiempo constante (sin tener en cuenta el tiempo empleado en la rutina de asignación de memoria). Sin embargo, en una situación habitual se añaden elementos a un array con mucha menos frecuencia que los que se buscan dentro de él, por lo que wxSortedArray puede suponer enormes mejoras de rendimiento en comparación con wxArray. Por último, debe tenerse en cuenta que, al igual que wxArray, wxSortedArray solo puede utilizarse para almacenar tipos enteros o punteros.

La clase wxObjArray trata sus elementos como "objetos". Puede borrarlos cuando se eliminan de la matriz (invocando el destructor correcto) y copiarlos utilizando el constructor de copia de objetos. Para implementar este comportamiento, la definición de las matrices wxObjArray se divide en dos partes: en primer lugar, se debe declarar la nueva clase wxObjArray utilizando la macro WX_DECLARE_OBJARRAY() y, a continuación, se debe incluir el fichero que define la implementación de tipo plantilla: <wx/arrimpl.cpp> y definir la clase array con la macro WX_DEFINE_OBJARRAY() desde un punto en el que la declaración completa (en lugar de "hacia adelante") de la clase de elementos array esté en el ámbito. Como probablemente suena muy complicado aquí hay un ejemplo:

#include <wx/dynarray.h>
 
// Debemos declarar hacia adelante el array porque se utiliza
// dentro de la declaración de la clase.
class MyDirectory;
class MyFile;
 
// Esto define dos nuevos tipos: ArrayOfDirectories y ArrayOfFiles que
// pueden ser usados como se muestra abajo.
WX_DECLARE_OBJARRAY(MyDirectory, ArrayOfDirectories);
WX_DECLARE_OBJARRAY(MyFile,      ArrayOfFiles);
 
class MyDirectory
{
    // ...
    ArrayOfDirectories m_subdirectories; // All subdirectories
    ArrayOfFiles       m_files;          // All files in this directory
};
 
// ...
 
// Ahora que tenemos la declaración MyDirectory en el ámbito podemos 
// terminar la definición de ArrayOfDirectories -- hay que tener en cuenta 
// que esto se expande en algo de código C++ y por lo tanto sólo debe ser 
// compilado una vez (es decir, no se debe poner esto en la cabecera, sino 
// en un archivo fuente o se obtendrán errores de vinculación)
#include <wx/arrimpl.cpp> // ¡Es un encantamiento mágico que hay que hacer!
WX_DEFINE_OBJARRAY(ArrayOfDirectories);
 
// esto es todo

No es tan elegante como escribir esto:

typedef std::vector<MyDirectory> ArrayOfDirectories;

Pero no es tan complicado y permite compilar el código con cualquier compilador de C++, por tonto que sea.

Hay que recordar incluir <wx/arrimpl.cpp> justo antes de cada ocurrencia de WX_DEFINE_OBJARRAY() en en código, incluso si se tienen varias en el mismo fichero.

Sin embargo, las cosas son mucho más sencillas para wxArray y wxSortedArray: basta con escribir:

WX_DEFINE_ARRAY_INT(int, ArrayOfInts);
WX_DEFINE_SORTED_ARRAY_INT(int, ArrayOfSortedInts);

Solo hay una macro DEFINE y no hay necesidad de una DECLARE separada. Para las matrices de los tipos primitivos, las macros WX_DEFINE_ARRAY_CHAR/SHORT/INT/SIZE_T/LONG/DOUBLE deben ser usadas dependiendo del tamaño de los valores (observar que almacenar valores de tipo pequeño, p.ej. shorts, en una matriz de tipo grande, p.ej. ARRAY_INT, no funciona en todas las arquitecturas).

Macros para la definición de matrices de plantillas

Para utilizar un array primero hay que definir la clase array. Esto se hace con la ayuda de las macros de esta sección. La clase de los elementos del array debe estar (al menos) declarada de antemano para las macros WX_DEFINE_ARRAY(), WX_DEFINE_SORTED_ARRAY() y WX_DECLARE_OBJARRAY() y debe estar completamente declarada antes de utilizar la macro WX_DEFINE_OBJARRAY().

Para complicar aún más las cosas, el operador "->" definido por defecto para los iteradores de array por estas macros solo tiene sentido si el tipo del elemento del array no es un puntero propiamente dicho y, aunque sigue funcionando, esto provoca advertencias de algunos compiladores y para evitarlas se deberían utilizar las versiones _PTR de las macros anteriores. Por ejemplo, para definir un array de punteros a double deberías usar:

WX_DEFINE_ARRAY_PTR(double *, MyArrayOfDoublePointers);

Hay que tener en cuenta que las macros anteriores generalmente solo son útiles para los tipos wxObject. Existen macros separadas para declarar un array de un tipo simple, como un int.

Se soportan los siguientes tipos simples:

  • int
  • long
  • size_t
  • double

Para crear una matriz de tipo simple, basta con añadir el tipo deseado en MAYÚSCULAS a la definición de la matriz.

Por ejemplo, utilice una de las siguientes variantes para una matriz de enteros:

  • WX_DEFINE_ARRAY_INT()
  • WX_DEFINE_EXPORTED_ARRAY_INT()
  • WX_DEFINE_USER_EXPORTED_ARRAY_INT()
  • WX_DEFINE_SORTED_ARRAY_INT()
  • WX_DEFINE_SORTED_EXPORTED_ARRAY_INT()
  • WX_DEFINE_SORTED_USER_EXPORTED_ARRAY_INT()

Tipos de array predefinidos

wxWidgets define los siguientes tipos de array dinámicos:

Para usarlos no se necesita ninguna macro; solo es necesario incluir dynarray.h.

Funciones miembro

wxArray()

template<typename T > wxArray< T >::wxArray()

Constructor por defecto.

wxArray()

template<typename T > wxArray< T >::wxArray(const wxArray< T > & array)

Realiza una copia superficial de matrices (es decir, no copia los objetos apuntados aunque la matriz de origen contenga los elementos de tipo puntero).

wxArray()

template<typename T > wxArray< T >::wxArray(std::initializer_list< T > list)

Construye el contenedor con el contenido de la lista initializer_list.

~wxArray()

template<typename T > wxArray< T >::~wxArray()

Este destructor no borra todos los elementos del array, para ello se puede utilizar la macro WX_CLEAR_ARRAY().

~wxSortedArray()

template<typename T > wxArray< T >::~wxSortedArray()

Este destructor no borra todos los elementos del array, para ello se puede utilizar la macro WX_CLEAR_ARRAY().

~wxObjArray()

template<typename T > wxArray< T >::~wxObjArray()

Este destructor borra todos los elementos pertenecientes al array.

Add()

template<typename T > void wxArray< T >::Add( T & item, size_t copies = 1 )

Añade el número dado de copias del elemento al array formado por los elementos de tipo T.

Esta versión se utiliza con wxObjArray. El array hará una copia del elemento y no tomará posesión del elemento original.

También se puede utilizar la macro WX_APPEND_ARRAY() para anexar todos los elementos de un array a otro, pero es más eficiente utilizar el parámetro copies y modificar los elementos en su lugar más tarde si se planea anexar muchos elementos.

Add()

template<typename T > void wxArray< T >::Add(T * item)

Añade el elemento al array formado por los elementos de tipo T.

Esta versión se utiliza con wxObjArray. El array tomará posesión del elemento, borrándolo cuando el elemento sea borrado del array. Hay que tener en cuenta que no se puede añadir más de un puntero ya que reutilizarlo llevaría a borrarlo dos veces (o más) provocando un fallo.

También se puede utilizar la macro WX_APPEND_ARRAY() para anexar todos los elementos de un array a otro, pero es más eficiente utilizar el parámetro copies y modificar los elementos en su lugar más tarde si se planea anexar muchos elementos.

Add()

template<typename T > size_t wxArray< T >::Add(T item)

Añade el elemento al array formado por los elementos de tipo T.

Esta versión se utiliza con wxSortedArray, devolviendo el índice donde se almacena el elemento.

Add()

template<typename T > void wxArray< T >::Add( T item, size_t copies = 1 )

Añade el número dado de copias del elemento al array formado por los elementos de tipo T.

Esta versión se utiliza con wxArray.

También se puede utilizar la macro WX_APPEND_ARRAY() para añadir todos los elementos de una matriz a otra, pero es más eficiente utilizar el parámetro copies y modificar los elementos en su lugar más tarde si se planea añadir muchos elementos.

AddAt()

template<typename T > void wxArray< T >::AddAt( T item, size_t index )

Inserta el elemento dado en la matriz en la posición de índice especificada.

hay que tener en cuenta que se alterará el orden del array si se da una posición incorrecta.

Esta función es útil junto con IndexForInsert() para una operación común de "insertar solo si no se encuentra".

Alloc()

template<typename T > void wxArray< T >::Alloc(size_t count)

Preasigna memoria para un número determinado de elementos del array.

Merece la pena llamarlo cuando se conoce de antemano el número de elementos que se van a añadir al array, ya que ahorrará reasignaciones de memoria innecesarias. Si el array ya tiene memoria suficiente para el número de elementos dado, no ocurre nada. En cualquier caso, el contenido existente de la matriz no se modifica.

Clear()

template<typename T > void wxArray< T >::Clear()

Esta función hace lo mismo que Empty() y además libera la memoria asignada al array.

Detach()

template<typename T > T* wxArray< T >::Detach(size_t index)

Elimina el elemento de la matriz, pero a diferencia de Remove(), no lo borra.

La función devuelve el puntero al elemento eliminado.

Empty()

template<typename T > void wxArray< T >::Empty()

Vacía el array.

Para las clases wxObjArray, esto destruye todos los elementos del array. Para wxArray y wxSortedArray esto no hace nada excepto marcar el array de estar vacío - esta función no libera la memoria asignada, utilizar Clear() para eso.

GetCount()

template<typename T > size_t wxArray< T >::GetCount() const

Devuelve el número de elementos del array.

Index()

template<typename T > int wxArray< T >::Index(T & item) const

Esta versión de Index() es sólo para wxSortedArray.

Busca el elemento en el array, utilizando la búsqueda binaria.

Se devuelve wxNOT_FOUND si no se encuentra el elemento, en caso contrario se devuelve el índice del elemento.

Index()

template<typename T > int wxArray< T >::Index( T & item, bool searchFromEnd = false ) const

Esta versión de Index() es sólo para wxArray y wxObjArray.

Busca el elemento en el array, empezando desde el principio o desde el final dependiendo del valor del parámetro searchFromEnd. Se devuelve wxNOT_FOUND si no se encuentra el elemento, en caso contrario se devuelve el índice del elemento.

Nota: Incluso para las clases wxObjArray, esta función no utiliza el operador "==" de los elementos del array. Busca exactamente el elemento dado en el array, por lo que sólo tendrá éxito si este elemento ha sido añadido previamente al array, pero fallará incluso si hay otro elemento idéntico en el array.

IndexForInsert()

template<typename T > size_t wxArray< T >::IndexForInsert(T item) const

Busca un lugar para insertar un elemento en la matriz ordenada (búsqueda binaria).

El índice devuelto está justo antes del primer elemento existente que es mayor o igual (según la función de comparación) al elemento dado.

Hay que hacer un trabajo extra para saber si el elemento ya existe en el array.

Esta función es útil junto con AddAt() para una operación común de "insertar sólo si no se encuentra".

Insert()

template<typename T > void wxArray< T >::Insert( T & item, size_t n, size_t copies = 1 )

Inserta el número dado de copias del elemento en el array antes del elemento existente n - así, Insert(algo, 0u) insertará un elemento de tal manera que se convertirá en el primer elemento del array.

wxSortedArray no tiene esta función porque la inserción en un lugar incorrecto rompería su condición de ordenado.

Por favor, ver Add() para una explicación de las diferencias entre las versiones sobrecargadas de esta función.

Insert()

template<typename T > void wxArray< T >::Insert( T * item, size_t n )

Inserta el número dado de copias del elemento en el array antes del elemento existente n - así, Insert(algo, 0u) insertará un elemento de tal manera que se convertirá en el primer elemento del array.

wxSortedArray no tiene esta función porque la inserción en un lugar incorrecto rompería su condición de ordenado.

Por favor, ver Add() para una explicación de las diferencias entre las versiones sobrecargadas de esta función.

Insert()

template<typename T > void wxArray< T >::Insert( T item, size_t n, size_t copies = 1 )

Inserta el número dado de copias del elemento en el array antes del elemento existente n - así, Insert(algo, 0u) insertará un elemento de tal manera que se convertirá en el primer elemento del array.

wxSortedArray no tiene esta función porque la inserción en un lugar incorrecto rompería su condición de ordenado.

Por favor, ver Add() para una explicación de las diferencias entre las versiones sobrecargadas de esta función.

IsEmpty()

template<typename T > bool wxArray< T >::IsEmpty() const

Devuelve true si el array está vacío, false en caso contrario.

Item()

template<typename T > T& wxArray< T >::Item(size_t index) const

Devuelve el elemento en la posición dada en el array.

Si el índice está fuera de los límites, se genera un error de aserción en las versiones de depuración, pero no se hace nada especial en la versión de lanzamiento.

El valor devuelto es de tipo "referencia al tipo de elemento del array" para todas las clases de array.

Last()

template<typename T > T& wxArray< T >::Last() const

Devuelve el último elemento del array, es decir, es lo mismo que llamar a "Item(GetCount() - 1)".

Si la matriz está vacía, se produce un error de aserción en el modo de depuración.

El valor devuelto es de tipo "referencia al tipo de elemento del array" para todas las clases de array.

Remove()

template<typename T > void wxArray< T >::Remove(T item)

Elimina un elemento del array por valor: se elimina el primer elemento del array igual a item, se producirá un fallo de assert si se intenta eliminar un elemento que no existe en el array.

Cuando un elemento es eliminado de wxObjArray es borrado por el array - utilizar Detach() si no se desea que esto ocurra. Por otro lado, cuando un objeto es eliminado de un wxArray no ocurre nada - debe ser eliminarlo manualmente si es necesario:

T *item = array[n];
array.Remove(item);
delete item;

Véase también la macro WX_CLEAR_ARRAY() que borra todos los elementos de un wxArray (se supone que contiene punteros).

Nótese que para arrays ordenados este método utiliza la búsqueda binaria para encontrar el elemento, por lo que no elimina necesariamente el primer elemento coincidente, sino el primero encontrado por la búsqueda binaria.

RemoveAt()

template<typename T > void wxArray< T >::RemoveAt( size_t index, size_t count = 1 )

Elimina del array los count elementos que comienzan en el índice.

Cuando un elemento es eliminado de wxObjArray es borrado por el array - utilizar Detach() si no se desea que esto ocurra. Por otro lado, cuando un objeto es eliminado de un wxArray no ocurre nada - debe ser eliminarlo manualmente si es necesario:

T *item = array[n];
delete item;
array.RemoveAt(n);

Véase también la macro WX_CLEAR_ARRAY() que borra todos los elementos de un wxArray (se supone que contiene punteros).

SetCount()

template<typename T > void wxArray< T >::SetCount( size_t count, T defval = T(0) )

Esta función asegura que el número de elementos del array es al menos count.

Si el array ya tiene count o más elementos, no se hace nada. En caso contrario, se añaden los elementos count - GetCount() y se inicializan al valor defval.

Shrink()

template<typename T > void wxArray< T >::Shrink()

Libera toda la memoria no utilizada por el array.

Si el programa sabe que no se añadirán nuevos elementos a la matriz, puede llamar a Shrink() para reducir el uso de memoria. Sin embargo, si se añade un nuevo elemento al array, se volverá a asignar algo de memoria extra.

Sort()

template<typename T > void wxArray< T >::Sort(CMPFUNC< T > compareFunction)

La notación "CMPFUNCT<T>" debe leerse como si tuviéramos la siguiente declaración:

template int CMPFUNC(T *primero, T *segundo);

Donde T es el tipo de los elementos del array. Es decir, es una función que devuelve int a la que se le pasan dos argumentos de tipo T*.

Ordena el array utilizando la función de comparación especificada: esta función debe devolver un valor negativo, cero o positivo según si el primer elemento que se le pasa es menor, igual o mayor que el segundo.

wxSortedArray no tiene esta función porque siempre está ordenado.

wxObjArray()

template<typename T > wxArray< T >::wxObjArray()

El constructor por defecto inicializa un objeto array vacío.

wxObjArray()

template<typename T > wxArray< T >::wxObjArray(const wxObjArray & array)

Realiza una copia profunda (es decir, también se copian los elementos de la matriz)

wxSortedArray()

template<typename T > wxArray< T >::wxSortedArray(const wxSortedArray & array)

Realiza una copia superficial de matrices (es decir, no copia los objetos apuntados aunque la matriz de origen contenga los elementos de tipo puntero)..

wxSortedArray()

template<typename T > wxArray< T >::wxSortedArray(int(*)(T first, T second) compareFunction)

No hay un constructor por defecto para las clases wxSortedArray - debe inicializarlo con una función que se utilizará para la comparación de elementos.

Es una función a la que se le pasan dos argumentos de tipo T donde T es el tipo de elemento del array y que debe devolver un valor negativo, cero o positivo según si el primer elemento que se le pasa es menor, igual o mayor que el segundo.

Operadores

operator=()

template<typename T > wxArray& wxArray< T >::operator=(const wxArray< T > & array)

Realiza una copia superficial de matrices (es decir, no copia los objetos apuntados aunque la matriz de origen contenga los elementos de tipo puntero).

operator=()

template<typename T > wxObjArray& wxArray< T >::operator=(const wxObjArray & array)

Realiza una copia profunda (es decir, también se copian los elementos de la matriz).

operator=()

template<typename T > wxSortedArray& wxArray< T >::operator=(const wxSortedArray & array)

Realiza una copia superficial de matrices (es decir, no copia los objetos apuntados aunque la matriz de origen contenga los elementos de tipo puntero).

Métodos y datos heredados

Esta clase hereda los métodos y datos miembro públicos y protegidos de