2009-04-21 11 views
6

Wszelkie sugestie dotyczące mojego przydziału na podstawie stosu? (z wyjątkiem sugestie, aby użyć klasy z członków publicznych/prywatnych)Ulepszenia dla tego przydziału stosu 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

Jaka jest moja pamięć pamięci C++? – paxdiablo

+0

Zastanawiasz się, czy istnieje jakikolwiek sposób, aby ją zoptymalizować, lub lepsze konwencje itp. – Unknown

+0

Dobra, ustalenie tytułu, aby było bardziej zrozumiałe. – paxdiablo

Odpowiedz

4

Zaimplementowano alokator na podstawie stosu. Nie możesz uwolnić się bez pozostawiania luk. Zwykle pula odnosi się do bloku sąsiadującej pamięci ze szczelinami o ustalonej wielkości, które są podwójnie połączone, aby umożliwić dodawanie i usuwanie stałego czasu.

Here's one możesz użyć jako przewodnika. Jest on zgodny z tymi samymi, co Twój, ale zawiera podstawowe iteratory nad przydzielonymi węzłami i używa szablonów do świadomości typów.

+0

Ach tak, to wydaje się być właściwym terminem. Myślałem, że nazywa się to pulą pamięci. – Unknown

2

dwa oczywiste problemy:

1/Ty nie masz deallocate().

2/A deallocate() będzie bardzo trudno napisać z twoją obecną strategią, chyba że zawsze będziesz zwolniony w dokładnie odwrotnej kolejności przydziału. Musisz uwzględnić przypadek, w którym klient chce zwolnić pamięć w środku używanej sekcji.

Oczywiście, jeśli zwolnisz zlecenie w odwrotnej kolejności, (2) nie jest to problemem. A jeśli nigdy w ogóle nie uwolnisz pamięci, (1) również nie stanowi to problemu.

To zależy od tego, co chcesz zrobić.

+0

Podobnie jak w przypadku zwykłej puli pamięci, wystarczy przydzielić kilka obiektów, a następnie zwolnić je wszystkie w jednym wywołaniu funkcji. Ale zupełnie zapomniałem o punkcie Sharptootha, że ​​być może będę musiał wywołać każdy z ich destruktorów, jeśli nie są to POD. – Unknown

+0

Wystarczy wywołać destruktory, jeśli mają uchwyty plików/inne obiekty otwarte, które nie żyją w puli. Jeśli wszystko przydzieli tylko pamięć i cała pamięć znajduje się w puli, nie musisz wywoływać destruktorów. –

1

Twoja sterty nie pozwalają na dealokację. W jaki sposób użyjesz go do obiektów przydzielonych z nowy w C++?

+0

Podnosisz dobry punkt, przypuszczam, myślałem tylko o tym, że będę zawierał POD. – Unknown

+0

Nawet z POD będziesz musiał dbać o usunięcie operatora.Jeśli tego nie zrobisz, zostanie użyty domyślny operator delete, który prawdopodobnie spowoduje awarię twojego programu. – sharptooth

+0

Co polecasz? Czy muszę zastąpić operatora globalnego usuwania? – Unknown

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

Niezły, nigdy nie robić takich rzeczy, można zakładać, że sizeof (size_t) == sizeof (void *), także to, co się dzieje, jeśli bytes==(size_t)(-1) to nie będzie działać

Dodatkowo musisz upewnić się, że wskaźniki, które zwracasz, są wyrównane. W przeciwnym razie wystąpiłoby problem. Musisz więc upewnić się, że bajty są wielokrotnością 4 lub 8 według twojej platformy.

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

Propozycja? Nie wymyślaj ponownie koła. Istnieje wiele dobrych bibliotek basenowych.

+0

Ale powodem, dla którego nie używałem char, jest to, że char nie ma gwarantowanego 1 bajtu. size_t według mojej wiedzy jest zawsze nieważny *, ponieważ typ może obejmować całą przestrzeń adresową. Również mój kompilator gcc nie pozwala mi wykonywać void * arytmetycznych. Ale masz punkt z wyrównaniem: jego kompromisem między czasoprzestrzenią. – Unknown

+1

Standardowo definiuje sizeof (char) = 1, standard nie definiuje sizeof (size_t) == sizeof (void *) nawet jest powszechne w praktyce, ale definiuje sizeof (intptr_t) == sizeof (void *) (ale intptr_t nie jest dostępny dla niektórych kompilatorów takich jak VC++). – Artyom

+0

"to kompromis czasoprzestrzenny." to jest pytanie o poprawność. Na niektórych platformach (takich jak ARM) proces może się nie powieść, jeśli wykonasz nieuprawniony dostęp. Ponadto twoje dane wykorzystują operacje atomowe (na przykład muteks), które zawiodłyby, gdyby nie były niezarejestrowane. – Artyom