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

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



Часть II

Глава 10. Управление памятью

Глава 11. Перегрузка

Глава 12. Множественное наследование

Глава 13. Уточнения понятия класса

Глава 14. Приведение типов

Глава 15. Шаблоны

Глава 16. Обработка исключений

Глава 17. Пространства имен

Глава 18. Препроцессор С

в части II описываются средства С++, появившиеся после выхода версии 1.0. Разбиение на главы основано на логических взаимосвязях между различными возможностями. Хронология их включения в C++ для языка в целом не существенна и здесь не отражена. Порядок глав тоже не играет большой роли.



Глава 10. Управление памятью

Никакому гению не преодолеть проклятия деталей.

Анонимный автор

10.1. Введение

в С++ есть оператор new для выделения памяти из кучи и оператор delete для освобождения выделенной памяти (см. раздел 2.11.2). Но иногда пользователю необходим более тщательный контроль над распределением и освобождением памяти.

Важный частный случай - выделение памяти на уровне часто используемого класса [2nd, стр. 177]. Многие программы создают и уничтожают больпюе число мелких объектов, принадлежащих нескольким важным классам, напри.мер узлы дерева или связанного списка, точки, линии, сообщения и т.д. На выделение и освобождение памяти для таких объектов с помощью распределителя общего назначения может уходить почти все время работы программы, приче.м память будет использоваться неэффективно. Здесь играют роль два фактора: затраты по времени и па.мяти, присущие универсальному распределителю, и фрагментация свободной памяти из-за того, что в ней создаются объекты разных размеров. Я обнаружил, что при.мепение специализированного распределителя, определенного на уровне класса, обычно позволяет вдвое увеличить скорость действия симулятора, компилятора или аналогичной профам.мы по сравнению с применением стандартного алгоритма управления памятью. Приходилось видеть и десятикратное ускорение в случаях, когда проблемы фрагментации были особенно остры.ми. Средства, включеш1ые в версию 2.0, позволяют добавить в класс распределитель (написанный самостоятельно или взятый из стандартной библиотеки) всего за несколько минут.

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

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

Вследствие всего этого механизм управления памятью в С++ (см. раздел 2.11.2) в версии 2.0 был пересмотрен. В основно.м усоверщенствования коснулись



механизмов контроля над распределением памяти, при этом предполагалось, что программист понимает, как это происходит. Эти механизмы должны были работать совместно с другими языковыми средства.ми, чтобы инкапсулировать те фрагменты кода, где осуществляется нестандартное управление памятью. Работа над ними завершилась в 1992 г. введением операторов operator new [ ] и operator delete [ ] управления па.мятью для массивов.

В нескольких случаях предложения исходили от моих друзей из компании Mentor Graphics, где на С-ы- была создана большая и сложная система CAD/CAM. Арчи Лахнер из Mentor подал мне несколько блестящих идей об управлении памятью, которые были учтены в версии 2.0.

10.2. Отделение распределения памяти и инициализации

Применявшийся до выхода 2.0 способ управлять распределением и освобождением памяти на уровне класса с помошью присваивания указателю this (см. раздел 3.9.) провоцировал ошибки и был объявлен устаревшим. В версии 2.0 в качестве альтернативы допускались раздельные выделение и инициализация памяти. Это значит, что инициализация выполняется конструктором после того, как память уже выделена каким-то независимы.м механизмо.м. Такой нрие.м позволяет использовать разные механизмы распределения, в том числе написанные пользователем. Память для статических объектов выделяется на стадии редактирования связей, па.мять под локальные объекты распределяется из стека, а для дина.мичес-ких объектов - с помошью подходящего operator new {). Освобождение памяти производится аналогично. Например:

class X { ... public:

void* operator new(size t sz) ; выделить sz байт void operator delete(void* p) ; освободить p

X(); инициализировать

X(int i); инициализировать

~X(); очистка

. . .

Тип size t - это зависящий от реализации интегральный тип, используемый для представления размеров объектов; он позаимствован из стандарта ANSI С.

Именно с помощью оператора new правильно выделяется и инициализируется память, если эти операции выполняются раздельно. Компилятор генерирует вызов распределителя памяти X: : operator new() и вызов конструктора X в месте вызова new для X. Логически X: : operator new() вызывается раньше конструктора. Поэтому он должен вернуть void*, а не X*. Конструктор создает объект уже в выделенной памяти.



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

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