2009-04-21 3 views
6

Любые предложения для моего распределителя на основе стека? (За исключением предложений, чтобы использовать класс с частными/общественными членами)Усовершенствования для этого распределителя стека 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++ ЧТО? – paxdiablo

+0

Просто интересно, есть ли какой-нибудь способ его оптимизации или более эффективные соглашения и т. Д. – Unknown

+0

Хорошо, исправляя заголовок, чтобы сделать его понятнее. – paxdiablo

ответ

4

Вы реализовали распределитель на основе стека. Вы не можете освободиться, не оставляя пробелов. Обычно пул относится к блоку смежной памяти с фиксированными размерами слотов, которые связаны вдвойне, позволяя добавлять и удалять постоянное время.

Here's one Вы можете использовать в качестве руководства. Он соответствует тем же строкам, что и ваш, но включает базовые итераторы над выделенными узлами и использует шаблоны для распознавания типов.

+0

А да, это, кажется, правильный термин. Я думал, что это называется пулом памяти. – Unknown

2

Две очевидные проблемы:

1/У вас нет deallocate().

2/A deallocate() будет очень сложно писать с помощью вашей текущей стратегии, если вы не собираетесь освобождать вас в точном обратном порядке выделения. Вам нужно будет обслуживать случай, когда клиент хочет освободить память в середине используемого раздела.

Конечно, если вы освободите себя в обратном порядке, (2) не проблема. И если вы никогда не освобождаете память вообще, (1) тоже не проблема.

Это зависит от того, что вы хотите.

+0

Ну, как обычный пул памяти, вы просто выделяете кучу объектов, а затем освобождаете их всех в 1 вызове функции. Но потом я полностью забыл о точке Sharptooth, что, возможно, мне нужно будет вызвать каждого из их деструкторов, если они не являются POD. – Unknown

+0

Вам нужно только вызвать деструкторы, если у них есть открытые файлы/другие объекты, которые не живут в пуле. Если все выделяет только память, и вся эта память находится в пуле, вам не нужно просто вызывать деструкторы. –

1

Ваша куча не разрешает освобождение. Как вы будете использовать его для объектов, выделенных новыми в C++?

+0

Вы поднимаете хороший момент, я полагаю, я думал только о том, чтобы содержать POD. – Unknown

+0

Даже с POD вам придется позаботиться о удалении оператора.Если вы этого не сделаете, будет использован оператор delete по умолчанию, который, скорее всего, приведет к краху вашей программы. – sharptooth

+0

Что вы рекомендуете? Нужно ли переопределить глобальный оператор удаления? – Unknown

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

Не хорошо, никогда не делать что-то подобное, вы предполагаете, что SizeOf (size_t) == SizeOf (недействительными *), а также то, что произойдет, если bytes==(size_t)(-1) это не будет работать

Кроме того, вам нужно убедиться, что указатели, которые вы возвращаете, выровнены. В противном случае у вас возникнут проблемы. Таким образом, вы должны убедиться, что байты кратного 4 или 8 в соответствии с вашей платформой.

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

Предложение? Не изобретайте велосипед. Есть много и хороших библиотек пула.

+0

Но причина, по которой я не использовал char, заключается в том, что char не гарантированно составляет 1 байт. size_t, насколько мне известно, всегда void *, потому что тип может охватывать все адресное пространство. Также мой gcc-компилятор не позволяет мне делать void * арифметику. Но у вас есть точка с выравниванием: ее компромисс между пространством и временем. – Unknown

+1

Стандартно defiantly определяет sizeof (char) = 1, стандарт не определяет sizeof (size_t) == sizeof (void *), даже если он распространен на практике, но он определяет sizeof (intptr_t) == sizeof (void *) (но intptr_t недоступен для некоторых компиляторов, таких как VC++). – Artyom

+0

«его компромисс между пространством и временем». это вопрос правильности. На некоторых платформах (например, ARM) процесс может выйти из строя, если вы выполняете неравномерный доступ. Кроме того, ваши данные используют атомарные операции (например, mutex), это может привести к поломке, если оно не будет выровнено. – Artyom

Смежные вопросы