Выбрать главу

А что нам проку от управления памятью, спросите Вы? Да хотя бы скорость. Когда выполняется 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* CPooclass="underline" :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 CPooclass="underline" :getSomeMemory(bytes); }

 void operator delete(void*) {}

};

// инициализация статических членов.

char CPooclass="underline" :buffer[8096];

char* CPooclass="underline" :position = CPooclass="underline" :buffer;

Чтобы довести его до более-менее приличного вида, нужно как минимум обрабатывать размер выделяемого блока и количество оставшейся памяти в буфере; сделать буфер нестатическим; при недостатке памяти выделять новый буфер-создавать новый экземпляр пула; статическими должны быть либо функция выделения памяти из пула либо указатель на свежий, незаполненный пул.

Несколько строк занудства.

Операционка неохотно берет себе память обратно. Возможно, освобожденный фрагмент вообще останется в ведении менеджера памяти самой программы, до ее завершения. Но конечно крупные куски она заглатывает тут же. Если возитесь с мелочью, проверьте этот момент на всякий случай; нет ничего приятнее свопа или уборки мусора в нужное время!

Глобальный оператор ::operator new() и глобальный оператор ::operator delete() не трогайте. Проще и намного умнее перегружать операторы в классах.

new, operator new и конструктор, а так же delete, operator delete и деструктор - АБСОЛЮТНО разные вещи. Как мы уже выяснили, их можно вызывать по отдельности. Не давайте себя запутать, если кто-нибудь будет говорить об операторе new - такого не бывает, бывает или оператор operator new(), или ключевое слово new.

Шаг 20 - Временные объекты. Неявные вызовы конструкторов и их подавление.

Не удается углубиться в какую-либо тему. Приходится касаться по верхам, потом переключаться на что-то другое. С другой стороны, может это и правильно, часто достаточно только знать, что есть ТАКОЕ решение, а изучить детально можно и позже, когда сделаешь окончательный выбор. Да и не очень это интересно - что за радость переписать двадцать страниц из учебника, или перевести статью какого-нибудь доктора CS? Объяснения которого в точности так же логичны, как рассказ Ивана Бездомного насчет "…Берлиоза зарезало трамваем, а тот заранее знал про масло, которое Аннушка пролила" - то есть логика и связь есть - но только для него самого.

Чтож, к делу.

А кто такие временные объекты? Локальные переменные с замечательными именами a, a1, a2, a_1, tmp1, tmp2? (Кстати ни за что не берите на работу болванов, которые так именуют переменные; пусть на FoxPro пишут. Думаю написать про это отдельный Шаг - причины для немедленного увольнения.) Вообще-то нет. Временные объекты - это объекты, которые не имеют имен в коде и неявно создаются компилятором. Поскольку неявные "подарки" компилятора иногда бывают очень некстати, лучше заранее знать, чего можно ожидать от него. А зачем он их создает? Первое - при выполнении преобразования типов, для вызова функций. Второе - для возвращения объекта из функции.