2009-04-21 11 views
6

¿Alguna sugerencia para mi asignador basado en pila? (A excepción de sugerencias para utilizar una clase con miembros privados/públicos)Mejoras para este asignador de pila C++?

struct Heap 
{ 
    void* heap_start; 
    void* heap_end; 
    size_t max_end; 

    Heap(size_t size) 
    { 
     heap_start = malloc(size); 
     heap_end = heap_start; 
     max_end = size + (size_t) heap_start; 
    } 

    ~Heap() 
    { 
     ::free(heap_start); 
    } 

    void* allocate(size_t bytes) 
    { 

     size_t new_end = ((size_t) heap_end) + bytes; 

     if(new_end > max_end) 
      throw std::bad_alloc(); 

     void* output = heap_end; 
     heap_end = (void*) new_end; 
     return output; 
    } 

} 
+0

¿Cómo es mi grupo de memoria C++ QUÉ? – paxdiablo

+0

Solo me pregunto si hay alguna manera de optimizarlo, o mejores convenciones, etc. – Unknown

+0

De acuerdo, arreglando el título para hacerlo más claro. – paxdiablo

Respuesta

4

Ha implementado un asignador basado en pila. No puedes liberarte sin dejar huecos. Por lo general, un grupo se refiere a un bloque de memoria contigua con ranuras de tamaño fijo, que están doblemente vinculadas para permitir agregar y eliminar un tiempo constante.

Here's one puede usar como guía. Está en la misma línea que la tuya, pero incluye iteradores básicos sobre nodos asignados, y usa plantillas para escribir.

+0

Ah sí, ese parece ser el término correcto. Pensé que se llamaba grupo de memoria. – Unknown

2

Dos problemas obvios:

1/Usted no tiene un deallocate().

2/A deallocate() será muy difícil escribir con su estrategia actual a menos que siempre vaya a desasignar en el orden inverso exacto de la asignación. Tendrá que atender el caso en el que un cliente quiere desasignar la memoria en el medio de la sección utilizada.

Por supuesto, si desasigna en orden inverso, (2) no es un problema. Y si nunca liberas memoria, (1) tampoco es un problema.

Depende de lo que quieras que haga.

+0

Bueno, como grupo de memoria habitual, solo asigna un grupo de objetos, y luego desasignarlos todos en una llamada de función. Pero luego me olvidé por completo del punto de Sharptooth de que podría necesitar llamar a cada uno de sus destructores si no son POD. – Unknown

+0

Solo necesita llamar a los destructores si tienen identificadores de archivos/otros objetos abiertos que no viven en el grupo. Si todo asigna solo memoria y toda esa memoria está en la agrupación, no es estrictamente necesario llamar a destructores. –

1

Su pila no permite la desasignación. ¿Cómo lo usará para los objetos asignados con new en C++?

+0

Supongo que sacas un buen punto, solo pensaba en contener POD. – Unknown

+0

Incluso con POD, tendrá que encargarse de la eliminación del operador.Si no lo hace, se usará la eliminación predeterminada del operador que probablemente bloqueará su programa. – sharptooth

+0

¿Qué me recomiendan? ¿Tendré que anular el operador de eliminación global? – Unknown

4
size_t new_end = ((size_t) heap_end) + bytes; 

No es bueno, no hacer las cosas por el estilo, se asume que sizeof (size_t) == sizeof (void *), también lo que sucede si bytes==(size_t)(-1) esto no funcionaría

Además, necesita asegurarse de que los punteros que devuelve estén alineados. De lo contrario, tendría problemas. Por lo tanto, debe asegurarse de que los bytes sean múltiplos de 4 u 8 según su plataforma.

class {... 
char *max_end,*head_end,*heap_start; 
}; 

... 
max_end=heap_start+size; 
... 
bytes=align_to_platform_specific_value(bytes); 
if(max_end-heap_end >= bytes) { 
    void* output = (void*)heap_end; 
    heap_end+=bytes; 
    return output; 
} 
throw std::bad_alloc(); 

Sugerencia? No reinventes la rueda. Hay muchas y buenas bibliotecas de pool.

+0

Pero la razón por la que no usé char es porque no se garantiza que sea de 1 byte. size_t que yo sepa es siempre nulo * porque un tipo podría abarcar todo el espacio de direcciones. También mi compilador gcc no me deja hacer la aritmética vacía *. Pero tiene un punto con la alineación: es una compensación de espacio/tiempo. – Unknown

+1

El estándar define defiantly sizeof (char) = 1, el estándar no define sizeof (size_t) == sizeof (void *) incluso es común en la práctica, pero sí define sizeof (intptr_t) == sizeof (void *) (pero intptr_t no está disponible para algunos compiladores como VC++). – Artyom

+0

"es una compensación de espacio/tiempo". es una pregunta correcta En algunas plataformas (como ARM), un proceso puede fallar si no se accede correctamente. Además, sus datos utilizan operaciones atómicas (por ejemplo, mutex) que fallarían si no están desalineados. – Artyom