|
||||
|
Шаг 19 - Управление памятью. Продолжение 1.
А что случается, когда компилятор видит ключевое слово delete? А кстати то же самое, только в обратном порядке. Сначала вызывает деструктор, потом вызывает operator delete(), прототип коего: 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; Чтобы довести его до более-менее приличного вида, нужно как минимум обрабатывать размер выделяемого блока и количество оставшейся памяти в буфере; сделать буфер нестатическим; при недостатке памяти выделять новый буфер-создавать новый экземпляр пула; статическими должны быть либо функция выделения памяти из пула либо указатель на свежий, незаполненный пул. Несколько строк занудства. Операционка неохотно берет себе память обратно. Возможно, освобожденный фрагмент вообще останется в ведении менеджера памяти самой программы, до ее завершения. Но конечно крупные куски она заглатывает тут же. Если возитесь с мелочью, проверьте этот момент на всякий случай; нет ничего приятнее свопа или уборки мусора в нужное время! Глобальный оператор ::operator new() и глобальный оператор ::operator delete() не трогайте. Проще и намного умнее перегружать операторы в классах. new, operator new и конструктор, а так же delete, operator delete и деструктор - АБСОЛЮТНО разные вещи. Как мы уже выяснили, их можно вызывать по отдельности. Не давайте себя запутать, если кто-нибудь будет говорить об операторе new - такого не бывает, бывает или оператор operator new(), или ключевое слово new. |
|
||
Главная | Контакты | Нашёл ошибку | Прислать материал | Добавить в избранное |
||||
|