перегрузка нового и удаление C ++ для отслеживания выделения памяти - PullRequest
1 голос
/ 08 марта 2011

Мне нужна помощь в понимании кода, приведенного ниже ... allocate - это функция, которая будет вызвана перегруженным оператором new для выделения памяти. У меня возникли проблемы, пытаясь понять, в частности, следующие броски:

*static_cast<std::size_t*>(mem) = pAmount; //please explain?

return static_cast<char*>(mem) + sizeof(std::size_t); //? 

и ..

// get original block
void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t); //?

код показан ниже:

const std::size_t allocation_limit = 1073741824; // 1G
    std::size_t totalAllocation = 0;

    void* allocate(std::size_t pAmount)
    {
        // make sure we're within bounds
        assert(totalAllocation + pAmount < allocation_limit);

        // over allocate to store size
        void* mem = std::malloc(pAmount + sizeof(std::size_t));
        if (!mem)
            return 0;

        // track amount, return remainder
        totalAllocation += pAmount;
        *static_cast<std::size_t*>(mem) = pAmount;

        return static_cast<char*>(mem) + sizeof(std::size_t);
    }

    void deallocate(void* pMemory)
    {
        // get original block
        void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t);

        // track amount
        std::size_t amount = *static_cast<std::size_t*>(mem);
        totalAllocation -= pAmount;

        // free
        std::free(mem);
    }

Ответы [ 4 ]

6 голосов
/ 08 марта 2011

Распределитель отслеживает размер выделений, сохраняя их вместе с блоками, которые он обслуживает, для клиентского кода. Когда его просят о блоке pAmount байтов, он выделяет дополнительные sizeof(size_t) байтов в начале и сохраняет там размер. Чтобы достичь этого размера, он интерпретирует указатель mem, полученный из malloc, как size_t* и разыменовывает его (*static_cast<std::size_t*>(mem) = pAmount;). Затем он возвращает остаток блока, который начинается с mem + sizeof(size_t), поскольку это та часть, которую клиент может использовать.

При освобождении он должен передавать точный указатель, полученный от malloc до free. Чтобы получить этот указатель, он вычитает sizeof(size_t) байтов, добавленных в функцию-член allocate.

В обоих случаях приведение к char* необходимо, поскольку арифметика указателей на указателях void не допускается.

2 голосов
/ 08 марта 2011

void * allocate (std :: size_t pAmount)

выделяет pAmount памяти плюс место для хранения размера

|-size-|---- pAmount of memory-----|

   ^
   |

«allocate» вернет указатель только что вставил поле размера.

void deallocate(void* pMemory)

переместит указатель обратно в начало

|-size-|---- pAmount of memory-----|

^
|

и освободи его.

1.)

std::size_t mySize = 0;

void * men = & mySize;

// same as: mySize = 42;
*static_cast<std::size_t*>(mem) = 42;

std::cout << mySize;
// prints "42"

2.)

`return static_cast<char*>(mem) + sizeof(std::size_t);
// casts void pointer mem to a char* so that you can do pointer arithmetic.
// same as

char *myPointer = (char*)mem;

// increment myPointer by the size of size_t
return myPointer + sizeof(std::size_t);

3.)

`void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t);`
// mem points size of size_t before pMemory
0 голосов
/ 08 марта 2011

приведение необходимо для получения правильного смещения, поскольку void * не является типом с размером.

при написании

return static_cast (mem) + sizeof (std:: size_t);

указатель приводится к символу * перед добавлением смещенных байтов.

то же самое вычитается при освобождении.

0 голосов
/ 08 марта 2011

Чтобы узнать, сколько памяти нужно очистить при ее удалении (и предоставить некоторую диагностику), распределитель сохраняет размер в дополнительной выделенной памяти.

* static_cast (mem) = pAmount; // объясните пожалуйста?

Это занимает выделенную память и сохраняет количество выделенных байтов в этом месте. Приведение обрабатывает необработанную память как size_t для целей хранения.

return static_cast (mem) + SizeOf (станд :: size_t); //

Это перемещается вперед за байты размера к фактической памяти, которую ваше приложение будет использовать, и возвращает этот указатель.

void * mem = static_cast (pMemory) - SizeOf (станд :: size_t); //

Это возвращает блок, ранее возвращенный пользователю, и возвращается к «реальному» выделенному блоку, который ранее сохранял размер. Нужно сделать проверки и восстановить память.

...