2009-04-21 13 views
6

Qualche suggerimento per l'allocatore basato sullo stack? (Fatta eccezione per i suggerimenti di utilizzare una classe con membri privati ​​/ pubblici)Miglioramenti per questo allocatore di stack 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

Come è il mio pool di memoria C++ COSA? – paxdiablo

+0

Basta chiedersi se c'è un modo per ottimizzarlo, o meglio convenzioni ecc. – Unknown

+0

Ok, aggiustando il titolo per renderlo più chiaro. – paxdiablo

risposta

4

Hai implementato un allocatore basato su stack. Non puoi liberare senza lasciare spazi vuoti. Di solito un pool fa riferimento a un blocco di memoria contigua con slot di dimensioni fisse, che sono doppiamente collegati per consentire l'aggiunta e l'eliminazione di tempo costante.

Here's one è possibile utilizzare come guida. È sulla stessa linea del tuo ma include iteratori di base sui nodi allocati e utilizza i modelli per essere di tipo type.

+0

Ah sì, sembra essere il termine corretto. Ho pensato che fosse chiamato un pool di memoria. – Unknown

2

Due problemi evidenti:

1/Tu non hai un deallocate().

2/A deallocate() sarà molto difficile scrivere con la strategia corrente, a meno che non si sia sempre in grado di deallocare esattamente nell'ordine inverso di allocazione. Avrai bisogno di soddisfare il caso in cui un cliente vuole deallocare la memoria nel mezzo della sezione utilizzata.

Naturalmente, se si effettua deallocate in ordine inverso, (2) non è un problema. E se non si libera mai memoria, (1) non è un problema.

Dipende da ciò che si desidera che faccia.

+0

Come un consueto pool di memoria, basta allocare un gruppo di oggetti e quindi deallocarli tutti in 1 chiamata di funzione. Ma poi ho completamente dimenticato il punto di vista di Sharp che potrei aver bisogno di chiamare ognuno dei loro distruttori se non sono POD. – Unknown

+0

È necessario chiamare i distruttori solo se hanno maniglie di file/altri oggetti aperti che non vivono nel pool. Se tutto assegna solo la memoria e tutta la memoria è nel pool, non è strettamente necessario chiamare i distruttori. –

1

L'heap non consente la deallocazione. Come lo userete per oggetti assegnati con new in C++?

+0

Mi sembra utile, suppongo, stavo solo pensando di contenere i POD. – Unknown

+0

Anche con POD dovrai occuparti dell'eliminazione dell'operatore.Se non lo fai, verrà utilizzata l'eliminazione dell'operatore predefinito che probabilmente causerà il crash del programma. – sharptooth

+0

Che cosa mi consiglia? Dovrò sovrascrivere l'operatore di cancellazione globale? – Unknown

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

Non va bene, non fare cose del genere, si assume che sizeof (size_t) == sizeof (void *), anche cosa succede se bytes==(size_t)(-1) questo non avrebbe funzionato

Inoltre, è necessario assicurarsi che i puntatori di ritorno siano allineati. Altrimenti avresti problemi. Quindi è necessario assicurarsi che i byte siano multipli di 4 o 8 in base alla propria piattaforma.

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(); 

Suggerimento? Non reinventare la ruota. Ci sono molte e buone librerie di biliardo.

+0

Ma il motivo per cui non ho usato char è perché non è garantito che il char sia 1 byte. size_t a mia conoscenza è sempre nullo * perché un tipo può estendersi su tutto lo spazio degli indirizzi. Anche il mio compilatore gcc non mi permette di fare il vuoto * aritmetico. Ma tu hai un punto con l'allineamento: è un compromesso spazio/tempo. – Unknown

+1

Definisce defiantly sizeof (char) = 1, lo standard non definisce sizeof (size_t) == sizeof (void *) anche se è comune nella pratica, ma definisce sizeof (intptr_t) == sizeof (void *) (ma intptr_t non è disponibile per alcuni compilatori come VC++). – Artyom

+0

"è un compromesso spazio/tempo". è una domanda di correttezza. Su alcune piattaforme (come ARM) un processo potrebbe fallire se si esegue l'accesso non allineato. Inoltre, i tuoi dati utilizzano operazioni atomiche (ad esempio mutex) che potrebbero essere in errore se non è allineato. – Artyom