Управление ресурсами
Управление ресурсами
Еще одна проблема поддержки нескольких интерфейсов из одного объекта становится яснее, если исследовать схему использования клиентом метода DynamicCast. Рассмотрим следующую клиентскую программу:
void f(void)
{
IFastString *pfs = 0;
IPersistentObject *ppo = 0;
pfs = CreateFastString(«Feed BOB»);
if (pfs) {
ppo = (IPersistentObject *) pfs->DynamicCast(«IPersistentObject»);
if (!ppo) pfs->Delete();
else { ppo->Save(«C:\autoexec.bat»);
ppo->Delete(); }
}
}
Хотя вначале объект был связан через свой интерфейс IFastString , клиентский код вызывает метод Delete через интерфейс IPersistentObject. С использованием свойства C++ о множественном наследовании это вполне допустимо, так как все таблицы vtbl , порожденные классом IExtensibleObject, укажут на единственную реализацию метода Delete . Теперь, однако, пользователь должен хранить информацию о том, какие указатели связаны с какими объектами, и вызывать Delete только один раз на объект. В случае простого кода, приведенного выше, это не слишком тяжелое бремя. Для более сложных клиентских кодов управление этими связями становится делом весьма сложным и чреватым ошибками. Одним из способов упрощения задачи пользователя является возложение ответственности за управление жизненным циклом объекта на реализацию. Кроме того, разрешение клиенту явно удалять объект вскрывает еще одну деталь реализации: тот факт, что объект находится в динамически распределяемой памяти (в «куче», on the heap).
Простейшее решение этой проблемы – ввести в каждый объект счетчик ссылок, который увеличивается, когда указатель интерфейса дублируется, и уменьшается, когда указатель интерфейса уничтожается. Это предполагает изменение определения IExtensibleObject с
class IExtensibleObject
{
public:
virtual void *DynamicCast (const char* pszType) =0;
virtual void Delete(void) = 0;
};
на
class IExtensibleObject
{
public:
virtual void *DynamicCast(const char* pszType) = 0;
virtual void DuplicatePointer(void) = 0;
virtual void DestroyPointer(void) = 0;
};
Разместив эти методы, все пользователи IExtensibleObject должны теперь придерживаться следующих двух соображений:
1) Когда указатель интерфейса дублируется, требуется вызов DuplicatePointer.
2) Когда указатель интерфейса более не используется, следует вызвать DestroyPointer.
Эти методы могут быть реализованы в каждом объекте: нужно просто фиксировать количество действующих указателей и уничтожать объект, когда невыполненных указателей не осталось:
class FastString : public IFastString,
public IPersistentObject
{
int mcPtrs;
// count of outstanding ptrs
// счетчик невыполненных указателей
public:
// initialize pointer count to zero
// сбросить счетчик указателя в нуль
FastString(const char *psz) : mcPtrs(0) { }
void DuplicatePointer(void)
{
// note duplication of pointer
// отметить дублирование указателя
++mcPtrs;
}
void DestroyPointer(void)
{
// destroy object when last pointer destroyed
// уничтожить объект, когда уничтожен последний указатель
if (-mcPtrs == 0) delete this;
}
: : :
};
Этот совершенно стандартный код мог бы просто быть включен в базовый класс или в макрос С-препроцессора, чтобы его могли использовать все реализации.
Чтобы поддерживать эти методы, все программы, которые манипулируют или управляют указателями интерфейса, должны придерживаться двух простых правил DuplicatePointer/DestroyPointer. Для реализации FastString это означает модификацию двух функций. Функция CreateFastString берет начальный указатель, возвращаемый новым оператором C++, и копирует его в стек для возврата клиенту. Следовательно, необходим вызов DuplicatePointer:
IFastString* CreateFastString(const char *psz)
{
IFastString *pfsResult = new FastString(psz);
if (pfsResult) pfsResult->DuplicatePointer();
return pfsResult;
}
Реализация копирует указатель и в другом месте – в методе Dynamic_Cast:
void *FastString::Dynamic_Cast(const char *pszType)
{
void *pvResult = 0;
if (strcmp(pszType, «IFastString») == 0) pvResult = static_cast<IFastString*>(this);
else if (strcmp(pszType, «IPersistentObject») == 0) pvResult = static_cast<IPersistentObject*>(this);
else if (strcmp(pszType, «IExtensibleObject») == 0) pvResult = static_cast<IFastString*>(this);
else return 0;
// request for unsupported interface
// запрос на неподдерживаемый интерфейс
// pvResult now contains a duplicated pointer, so
// we must call DuplicatePointer prior to returning
// теперь pvResult содержит скопированный указатель,
// поэтому нужно перед возвратом вызвать DuplicatePointer
((IExtensibleObject*)pvResult)->DuplicatePo1nter();
return pvResult;
}
С этими двумя усовершенствованиями соответствующий код пользователя становится значительно более однородным и прозрачным:
void f(void)
{
IFastString *pfs = 0;
IPersistentObject *ppo = 0;
pfs = CreateFastString(«Feed BOB»);
if (pts) {
рро = (IPersistentObject *) pfs->DynamicCast(«IPersistentObject»);
if (ppo) { ppo->Save(«C:\autoexec.bat»);
ppo->DestroyPointer(); }
pfs->DestroyPointer(); }
}
Поскольку каждый указатель теперь трактуется как автономный объект с точки зрения времени жизни, клиенту можно не интересоваться тем, какой указатель соответствует какому объекту. Вместо этого клиент просто придерживается двух простых правил и предоставляет объектам самим управлять своим временем жизни. При желании способ вызова DuplicatePointer и DestroyPointer можно легко скрыть за интеллектуальным указателем (smart pointer) C++.
Использование этой схемы вычисления ссылок позволяет объекту весьма единообразно выставлять множественные интерфейсы. Возможность выставления нескольких интерфейсов из одного класса реализации позволяет типу данных участвовать в различных контекстах. Например, новая постоянная подсистема могла бы определить собственный интерфейс для управления автозагрузкой и автозаписью объектов на некоторый специализированный носитель. Класс FastString мог бы добавить поддержку этих возможностей простым наследованием от постоянного интерфейса этой подсистемы. Добавление этой поддержки никак не повлияет на уже установленные базы клиентов, которые, может быть, используют прежний постоянный интерфейс для записи и загрузки строки на диск. Механизм согласования интерфейсов на этапе выполнения может служить краеугольным камнем для построения динамической системы из компонентов, которые могут изменяться со временем.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Работа с ресурсами локальной сети
Работа с ресурсами локальной сети Стандартным объектом, позволяющим выполнять типовые операции с локальной сетью, является WshNetwork. С помощью этого объекта можно:? узнать сетевое имя компьютера, имя текущего пользователя и название домена, в котором он
4.15.3. Управление стримером
4.15.3. Управление стримером Управление стримером выполняет программа int. Она входит в состав пакета mt-st, который обычно входит в состав дистрибутива. Эта программа точно есть в дистрибутивах Red Hat и Mandrake Linux. Программа mt использует устройство /dev/nftape, которое является ссылкой
5.8. Управление протоколированием
5.8. Управление протоколированием Этот раздел посвящен демону syslogd, а также управлению протоколированием сообщений системы и ядра с помощью этого демона. Прежде всего следует отметить, что демон находится в пакете sysklogd (если вы, конечно, используете Red Hat-совместимую
Управление финансами
Управление финансами Страница программы: http://www.saotron.ruСтатус: FreewareВести домашнюю бухгалтерию при мобильном образе жизни уж очень тяжко. Разве учтешь все эти перехваченные в пути газеты, бизнес-ланчи и прочие мелочи, из которых и складывается львиная доля расходов. Поди
10.4.2. Управление стримером
10.4.2. Управление стримером Управление стримером выполняет программа mt. Она входит в состав пакета mt-st, который обычно входит в состав дистрибутива (в дистрибутивах, основанных на Red Hat, он присутствует). Программа mt использует устройство /dev/nftape, которое является
Взаимодействие с тематически близкими ресурсами
Взаимодействие с тематически близкими ресурсами Организация взаимодействия с тематически близкими ресурсами может носить различный характер. Как правило, оно обоюдовыгодно, например, можно обменяться с другими сайтом баннерами, ссылками или информерами. Организация
Управление ресурсами
Управление ресурсами Еще одна проблема поддержки нескольких интерфейсов из одного объекта становится яснее, если исследовать схему использования клиентом метода DynamicCast. Рассмотрим следующую клиентскую программу:void f(void){IFastString *pfs = 0;IPersistentObject *ppo = 0;pfs = CreateFastString(«Feed BOB»);if
Управление ресурсами и IUnknown
Управление ресурсами и IUnknown Как было в случае с DuplicatePointer и DestroyPointer из предыдущей главы, методы AddRef и Release из IUnknown имеют очень простой протокол, которого должны придерживаться все, кто пользуется указателями этих интерфейсов. Эти правила освобождают клиента от
Глава 3 Управление ресурсами
Глава 3 Управление ресурсами Ресурс – это нечто такое, что после использования должно быть возвращено системе. Если этого не сделать, случаются неприятности. В программах на C++ наиболее часто используемым ресурсом является динамическая память (если вы выделяете память и
Правило 13: Используйте объекты для управления ресурсами
Правило 13: Используйте объекты для управления ресурсами Предположим, что мы работаем с библиотекой, моделирующей инвестиции (то есть акции, облигации и т. п.), и классы, представляющие разные виды инвестиций, наследуются от корневого класса Investment:class Investment {...} // корневой
Правило 14: Тщательно продумывайте поведение при копировании классов, управляющих ресурсами
Правило 14: Тщательно продумывайте поведение при копировании классов, управляющих ресурсами В правиле 13 изложена идея Получение Ресурса Есть Инициализация (Resource Acquisition Is Initialization – RAII), лежащая в основе создания управляющих ресурсами классов. Было также показано, как эта
8.3. Использование конструкторов и деструкторов для управления ресурсами (RAII)
8.3. Использование конструкторов и деструкторов для управления ресурсами (RAII) ПроблемаДля класса, представляющего некоторый ресурс, требуется использовать конструктор для получения этого ресурса и деструктор для его освобождения. Эта методика часто называется
Управление доступом
Управление доступом Основное преимущество средства алиасов в том, что оно может быть использовано в комбинации с параметром DatabaseAccess = NONE из файла firebird.conf для ограничения доступа к файлам баз данных - доступ разрешен только к файлам, указанным в aliases.conf.Алиасы баз данных
Параметры, связанные с ресурсами
Параметры, связанные с ресурсами CpuAffinityMaskВерсии 1.5 и выше под Windows.cpu_affinityВерсии до Firebird 1.5 под Windows.В Суперсервере Firebird под Windows могут быть проблемы с операционной системой, постоянно переключающей процесс Суперсервера туда и сюда между процессорами на машинах SMP. В списках