|
Программирование >> Полиморфизм без виртуальных функций в с++
Деструктор, наоборот, уничтожает объект, но не освобождает его память, полагая, что это сделает 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 О имеется очевидная и намеренная асимметрия: первый можно перегружать, второй - нет. Это
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |