Идиомы и стили С++ - страница 17
>void operator delete (void* to_free_mem);
Параметр есть указатель на освобождаемую память. Да, но в нашем примере НЕ НАДО ничего освобождать. Мы сами добыли память, сами и освободим. Что делать? Вообще не употреблять delete (ключевое слово, не оператор). А употребить только деструктор.
>ourObject-›~CClass();
Но с другой стороны, не следует навечно занимать память.Это нехорошо. Отдавать нужно так же, как и брали. Брали malloc() - отдаем через free(). Брали в стеке - ничего не делаем, само освободится. А может, брали через operator new() - тогда освобождаем через operator delete(). Вы наверное поняли, что сырую память можно взять через чистый оператор operator new():
>// взяли память
>char* piece_of_memory = operator new(100000000);
>// положили на место.
>operator delete (piece_of_memory);
Вроде управились со всем. Надо только запомнить, что всегда (превсегда) выделение и освобождение памяти должно идти только через комплементарные пары функций и механизмов. Потому что они (механизмы) совершенно друг друга не понимают. И память, выделенная через malloc, с точки зрения пары new-delete совсем не выделенная. А удаленная через free не удаленная. И наоборот. Полная несовместимость во все стороны.
А что нам проку от управления памятью, спросите Вы? Да хотя бы скорость. Когда выполняется operator new(), программа в общем случае обращается к операционной системе. Операционка, как Вы понимаете, не в восторге от толкающихся вокруг нее процессов и потоков, наперебой просящих у нее кусочки памяти, и выдает память в порядке очереди, к тому же у нее есть любимчики, да еще и себе нужно оставить… Ведет себя в точности так же, как нормальный начальник компьютерного отдела при распределении новой техники. Так что выгоднее сразу хапнуть достаточное количество памяти, а потом самостоятельно ее раздавать объектам.
А что касается освобождения памяти в нашем примере, то это вообще ураган: не нужно разрушать объекты по отдельности; Вы просто хрясь! - и освобождаете буфер целиком. Интересно, что чувствуют при этом объекты?
Конечно, нужно немного усложнить код, чем наши жалкие две строки. Следует "шмат памяти" оформить в виде класса, так чтобы выдавать память объектам последовательно. У объектов перегрузить операторы operator new() так, чтобы память бралась где нам надо, и operator delete() так чтобы он ничего не делал. И "шмат" называть "пулом". А то не поймут.
Я лишь чуть-чуть усложняю класс, только чтоб показать.
>#include ‹stdlib.h›
>// Класс пула
>class CPool {
>public:
> static char buffer[8096]; // статический буфер
> static char* position; // текущая позиция
> static void* getSomeMemory(size_t); // получить немного памяти
>};
>// вот получаем немного памяти.
>void* CPool::getSomeMemory(size_t bytes) {
> void* ret_val = position; // вернуть надо текущую позицию.
> position+=bytes; // а счетчик увеличить
> return ret_val;
>}
>// Это так… эксперимент.
>// Класс с собственным управлением памятью.
>class CThat {
>private:
> int m_some_number; // не знаю что.
>public:
> // перегруженные operator new, operaton delete
> void* operator new(size_t bytes) { return CPool::getSomeMemory(bytes); }
> void operator delete(void*) {}
>};
>// инициализация статических членов.
>char CPool::buffer[8096];
>char* CPool::position = CPool::buffer;
Чтобы довести его до более-менее приличного вида, нужно как минимум обрабатывать размер выделяемого блока и количество оставшейся памяти в буфере; сделать буфер нестатическим; при недостатке памяти выделять новый буфер-создавать новый экземпляр пула; статическими должны быть либо функция выделения памяти из пула либо указатель на свежий, незаполненный пул.
Несколько строк занудства.
Операционка неохотно берет себе память обратно. Возможно, освобожденный фрагмент вообще останется в ведении менеджера памяти самой программы, до ее завершения. Но конечно крупные куски она заглатывает тут же. Если возитесь с мелочью, проверьте этот момент на всякий случай; нет ничего приятнее свопа или уборки мусора в нужное время!