También puedes hacer una reserva grande al principio, y gestionar tu mismo esa memoria de forma manual.
Un ejemplo para ilustrar el asunto. En este caso se hace una reserva grande y se va utilizando para almacenar ints. Para optimizar el uso de memoria, los "slots" que estén vacíos van a almacenar un valor que se corresponde con el índice del siguiente "slot" vacío. Es decir, inicialmente, si suponemos una reserva para 3 ints, la memoria quedaría tal que:
| 1 | 2 | -1 |
El -1 es para indicar que no hay más memoria libre.
Cuando se libera un "slot" se borra su contenido y se vuelve a almacenar un índice (o -1 si es el único "slot" libre).
Para conocer el primer "slot" libre vamos a usar un puntero.
El ejemplo, dado que símplemente sirve para ilustrar la idea, carece de chequeos y asume que se usa correctamente... no costaría mucho modificarlo para que pudiese almacenar estructuras más complejas.
Ah sí... el main va a usar C++ porque así puedo simplificar el ejemplo.
Bueno, dicho esto, el código de ejemplo:
Código C++:
Ver original#include <vector>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int* data;
int nextIndex;
size_t size;
} Memory;
// Variable global... no acceder a ella directamente!!!!
Memory memory;
// Reserva memoria
// Si se hacen dos reservas consecutivas se producirán fugas de memoria!!!
// Retorna 1 si la reserva se ha realizado correctamente
int AllocMemory( size_t size )
{
memory.
data = (int*)malloc( size
* sizeof( int ) ); memory.size = size;
if( memory.data )
{
// Inicialización de la memoria
// Se almacenan los índices
size_t i;
for( i=0; i<size; ++i)
memory.data[ i ] = i+1;
memory.data[ size - 1] = -1;
// El primer slot libre es el primer elemento de la reserva
memory.nextIndex = 0;
}
else
memory.nextIndex = -1;
return memory.data != 0;
}
// Libera la memoria reservada
void ReleaseMemory( )
{
memory.data = 0;
memory.nextIndex = -1;
memory.size = 0;
}
// Reserva un nuevo slot y devuelve un puntero al mismo
// Si no quedan slots libres retornará 0
// El puntero devuelto no se encuentra inicializado
int* ReserveSlot( )
{
int* to_return = 0;
if( memory.nextIndex >= 0 )
{
to_return = &memory.data[ memory.nextIndex ];
memory.nextIndex = *to_return;
}
return to_return;
}
// Libera un slot previamente reservado
// Se asume que el puntero pertenece a la memoria reservada
void FreeSlot( int* ptr )
{
*ptr = memory.nextIndex;
memory.nextIndex = ptr - memory.data;
}
// Vuelca el contenido de la memoria por pantalla
// Para depurar
void DumpMemory( char* title )
{
size_t i;
for( i = 0; i < memory.size; ++i )
printf( "%10X", memory.
data[i
] ); }
int main(int , char **)
{
std::vector< int* > numbers;
int* slot = 0;
// Reservamos memoria
AllocMemory( 16 );
DumpMemory( "Reserva de memoria" );
// Reservamos 5 slots
while( numbers.size( ) < 5 )
{
slot = ReserveSlot( );
*slot = 0;
numbers.push_back( slot );
}
// Reservamos un 6º slot
slot = ReserveSlot( );
numbers.push_back( slot );
if( slot )
*slot = 0x100;
DumpMemory( "6 slots reservados" );
// Liberamos el 2º slot.
// Como el siguiente slot libre es el 7º, en esta posición se almacenará
// el valor 6 (recuerda que los índices empiezan en 0)
FreeSlot( numbers[ 1 ] );
// Eliminamos el slot del vector
numbers.erase( numbers.begin( ) + 1 );
DumpMemory( "Liberado 2o slot" );
// Liberamos el 4o slot.
// Como el siguiente slot libre es el 2º, en esta posición se almacenará
// el valor 1
FreeSlot( numbers[ 2 ] );
// Eliminamos el slot del vector
numbers.erase( numbers.begin( ) + 2 );
DumpMemory( "Liberado 4o slot" );
// Vamos a usar todos los slots:
while( numbers.size( ) < 16 )
{
slot = ReserveSlot( );
*slot = 0x12;
numbers.push_back( slot );
}
DumpMemory( "Sin slots libres" );
// Si intentamos una reserva nueva... fallará
slot = ReserveSlot( );
if( slot == 0 )
printf( "No hay slots libres!!!!\n" ); else
printf( "Slot reservado con éxito\n" );
// Si ahora liberamos, un slot intermedio,
// al ser el único slot libre,
// tendrá como siguiente índice -1 (0xFFFFFFFF)
FreeSlot( numbers[ 4 ] );
DumpMemory( "Un Slot libre (el 4o)" );
ReleaseMemory( );
return 0;
}
La ventaja que tiene este mecanismo es que garantizas la memoria al inicio de tu código... además la puedes seguir usando como si fuese memoria dinámica que vas reservando sobre la marcha...
Otra ventaja es que reduces la fragmentación de la memoria.
Un saludo