Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 66 67 68 [ 69 ] 70 71 72 ... 144


Деструктор, наоборот, уничтожает объект, но не освобождает его память, полагая, что это сделает operator delete {). Поэтому X: : operator delete {) принимает аргумент типа void*, а не X* .

Применимы обычные правила наследования, поэтому память для объектов производного класса выделяется с помощью operator new () из базового класса:

class Y : public X { объекты класса Y также распределяются

с помоцью X::operator new О

. . .

Чтобы этот фрагмент кода работал, X: : operator new() нужен аргумент, указываюн1ий, сколько памяти выделить: sizeof (Y) чаще всего не совпадает с sizeof (X). К сожалению, неопытные пользователи обычно удивляются, когда узнают, что нужно объявить этот аргумент, но не передавать его явно при вызове. Идея об определенной пользователем функции, фактический аргу.мент которой передает система , некоторыми усваивается с трудом. Но в качестве компенсации за излишнюю сложность базовый класс теперь может предоставлять услуги по выделению и освобождению памяти всем производным от него классам. Кроме того, ие возникает ненужных исключений из правил наследования.

10.3. Выделение памяти для массива

Определенный в классе оператор X: : operator new {) применяется только к индивидуальным объектам класса X (включая и объекты производных от X классов, в которых нет собственного operator new {)). Отсюда следует, что предложение

X* р = new Х[10];

не порождает вызова X: : operator new{), поскольку Х[10] - массив, а не объект типа X.

Это стало причиной претензий, поскольку пользователи не могли управлять распределением памяти для массивов. Однако я настаивал на том, что массив объектов X - пе то же самое, что X, а стало быть, использовать распределитель для класса X нельзя. Если бы его можно было применять к массива.м, то автору X: : operator new () пришлось бы специально рассматривать выделение памяти для .массива па всякий случай и тем самым усложнять алгоритм для стандартной ситуации. А если алгоритм не является настолько нужным, то зачем вообще писать специализированный распределитель? Кроме того, я подчеркнул, что управления выделением памяти для одномерных массивов типа X[d] все равно недостаточно: как тогда быть с много.мерными массивами X [ dl ] [ d2 ] ?

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



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

Рещение заключалось в том, чтобы просто определить пару функций специально для выделения и освобождения памяти под массивы:

class X { . . .

void* operator new(size t sz); выделение памяти для объектов void operator delete(void* p);

void* operator new[](size t sz); выделение памяти для массивов void operator delete[](void* p);

Распределитель памяти для массивов применим к массивам любой размерности. Как и любой другой распределитель, operator new [ ] должен предоставить запрощенное число байт; и не имеет значения, как будет использоваться эта память. В частности, распределителю не нужно задавать нн размерность массива, ни число элементов в нем. На введении операторов для выделения и освобождения памяти под массивы больше других настаивала Лаура Йекер (Layra Yaker) из компании Mentor Graphics.

10.4. Размещение объекта в памяти

с помощью единого механизма были решены две смежные проблемы:

□ нужен .механизм размещения объекта по фиксированному адресу. Например, объект, описывающий процесс, следует разместить по адресу, который диктует специализированная аппаратура;

□ требуется механизм распределения памяти для объекта из конкретной арены. Например, нужно разместить объект в разделяемой памяти многопроцессорной системы или в области, управляемой диспетчером устойчивых объектов.

Решение - разрешить перегрузку operator new() и предоставить синтаксис для передачи оператору new дополнительных аргу.ментов. Например, operator new () для раз.мешения объекта по фиксированно.му адресу .можно было определить так:

void* operator new(size t, void* p) {

return p; разместить объект по адресу р

а вызывать следующим образом:

void* buf = (void*)OxFOOF; специальный адрес

X* р2 = new(buf)X; конструируем X в области buf

вызывается operator new(sizeof(X),buf)



Из-за такого использования синтаксис new (buf) X для передачи дополнительных аргументов оператору operator new () получил название синтаксис размещения . Отметим, что первым аргументом любого operator new () является объе.м выделяемой памяти, и в данном случае раз.мер объекта подставляется системой неявно.

В то время я, мягко говоря, недооценил важность оператора размещения. При наличии размеп1ения оператор new перестает быть просто механизмо.м распределения памяти. Поскольку с фиксированным адресом можно ассоциировать произвольные логические свойства, то new приобретает черты универсального менеджера ресурсов.

Для конкретной арены operator new () можно определить так:

void* operator new(size t s, fast arena& a) {

return a.alloc(s);

a использовать следующим образом:

void f ( fast arena& arena) -.

X* p = new(arena)X; распределить X на арене . . .

Здесь предполагается, что f ast arena - это класс, который имеет фуикцию-члеп alloc (), применяющуюся для выделения памяти. Например:

class fast arena { ... char* maxp; char* freep;

char* expand(size t s); получить дополнительную память от

распределителя общего назначения

public:

void* alloc(size t s) { char* p = freep;

return ((freep+=s)<maxp) ? p : expand(s);

void free(void*) {) ничего не делает

clear О; освободить всю выделенную память

Такая арена специально предназначена для быстрого выделения памяти и почти мгновенного ее освобождения. Важной областью применения арен является предоставление специальной семантики управления памятью.

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

Между операторами operator new() и operator delete О имеется очевидная и намеренная асимметрия: первый можно перегружать, второй - нет. Это



1 ... 66 67 68 [ 69 ] 70 71 72 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика