Ver Mensaje Individual
  #3 (permalink)  
Antiguo 09/06/2015, 02:51
eferion
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 2 meses
Puntos: 204
Respuesta: Asignación de memoria dinámica.

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
  1. #include <vector>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4.  
  5. typedef struct
  6. {
  7.   int* data;
  8.   int nextIndex;
  9.   size_t size;
  10. } Memory;
  11.  
  12. // Variable global... no acceder a ella directamente!!!!
  13. Memory memory;
  14.  
  15. // Reserva memoria
  16. // Si se hacen dos reservas consecutivas se producirán fugas de memoria!!!
  17. // Retorna 1 si la reserva se ha realizado correctamente
  18. int AllocMemory( size_t size )
  19. {
  20.   memory.data = (int*)malloc( size * sizeof( int ) );
  21.   memory.size = size;
  22.   if( memory.data )
  23.   {
  24.     // Inicialización de la memoria
  25.     // Se almacenan los índices
  26.     size_t i;
  27.     for( i=0; i<size; ++i)
  28.       memory.data[ i ] = i+1;
  29.  
  30.     memory.data[ size - 1] = -1;
  31.  
  32.     // El primer slot libre es el primer elemento de la reserva
  33.     memory.nextIndex = 0;
  34.   }
  35.   else
  36.     memory.nextIndex = -1;
  37.  
  38.   return memory.data != 0;
  39. }
  40.  
  41. // Libera la memoria reservada
  42. void ReleaseMemory( )
  43. {
  44.   free( memory.data );
  45.   memory.data = 0;
  46.   memory.nextIndex = -1;
  47.   memory.size = 0;
  48. }
  49.  
  50. // Reserva un nuevo slot y devuelve un puntero al mismo
  51. // Si no quedan slots libres retornará 0
  52. // El puntero devuelto no se encuentra inicializado
  53. int* ReserveSlot( )
  54. {
  55.   int* to_return = 0;
  56.  
  57.   if( memory.nextIndex >= 0 )
  58.   {
  59.     to_return = &memory.data[ memory.nextIndex ];
  60.     memory.nextIndex = *to_return;
  61.   }
  62.  
  63.   return to_return;
  64. }
  65.  
  66. // Libera un slot previamente reservado
  67. // Se asume que el puntero pertenece a la memoria reservada
  68. void FreeSlot( int* ptr )
  69. {
  70.   *ptr = memory.nextIndex;
  71.   memory.nextIndex = ptr - memory.data;
  72. }
  73.  
  74. // Vuelca el contenido de la memoria por pantalla
  75. // Para depurar
  76. void DumpMemory( char* title )
  77. {
  78.   printf( "%s\n", title );
  79.   size_t i;
  80.   for( i = 0; i < memory.size; ++i )
  81.     printf( "%10X", memory.data[i] );
  82.   printf( "\n\n" );
  83. }
  84.  
  85. int main(int , char **)
  86. {
  87.   std::vector< int* > numbers;
  88.   int* slot = 0;
  89.  
  90.   // Reservamos memoria
  91.   AllocMemory( 16 );
  92.   DumpMemory( "Reserva de memoria" );
  93.  
  94.   // Reservamos 5 slots
  95.   while( numbers.size( ) < 5 )
  96.   {
  97.     slot = ReserveSlot( );
  98.     *slot = 0;
  99.     numbers.push_back( slot );
  100.   }
  101.  
  102.   // Reservamos un 6º slot
  103.   slot = ReserveSlot( );
  104.   numbers.push_back( slot );
  105.   if( slot )
  106.     *slot = 0x100;
  107.  
  108.   DumpMemory( "6 slots reservados" );
  109.  
  110.   // Liberamos el 2º slot.
  111.   // Como el siguiente slot libre es el 7º, en esta posición se almacenará
  112.   // el valor 6 (recuerda que los índices empiezan en 0)
  113.   FreeSlot( numbers[ 1 ] );
  114.  
  115.   // Eliminamos el slot del vector
  116.   numbers.erase( numbers.begin( ) + 1 );
  117.  
  118.   DumpMemory( "Liberado 2o slot" );
  119.  
  120.   // Liberamos el 4o slot.
  121.   // Como el siguiente slot libre es el 2º, en esta posición se almacenará
  122.   // el valor 1
  123.   FreeSlot( numbers[ 2 ] );
  124.  
  125.   // Eliminamos el slot del vector
  126.   numbers.erase( numbers.begin( ) + 2 );
  127.  
  128.   DumpMemory( "Liberado 4o slot" );
  129.  
  130.   // Vamos a usar todos los slots:
  131.   while( numbers.size( ) < 16 )
  132.   {
  133.     slot = ReserveSlot( );
  134.     *slot = 0x12;
  135.     numbers.push_back( slot );
  136.   }
  137.  
  138.   DumpMemory( "Sin slots libres" );
  139.  
  140.   // Si intentamos una reserva nueva... fallará
  141.   slot = ReserveSlot( );
  142.   if( slot == 0 )
  143.     printf( "No hay slots libres!!!!\n" );
  144.   else
  145.     printf( "Slot reservado con éxito\n" );
  146.  
  147.   // Si ahora liberamos, un slot intermedio,
  148.   // al ser el único slot libre,
  149.   // tendrá como siguiente índice -1 (0xFFFFFFFF)
  150.  
  151.   FreeSlot( numbers[ 4 ] );
  152.  
  153.   DumpMemory( "Un Slot libre (el 4o)" );
  154.  
  155.   ReleaseMemory( );
  156.  
  157.   return 0;
  158. }

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