Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Содержание сайт... 65535
Вызов хранимых ... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Invision Power ... 63892
Программируемая... 63815
Организация зап... 63446
Модуль Forms 60323
Создание отчето... 60296
ТЕХНОЛОГИИ ДОСТ... 56598
Пример работы с... 53707
Имитационное мо... 52001
Создание потоко... 51614
Реклама
Сейчас на сайте
Гостей: 6
На сайте нет зарегистрированных пользователей

Пользователей: 13,061
новичок: FooBar
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Моделирование автомойки на GPSS + Отчет + Блок схемы
Моделирование регулировочного участка цеха на GPSS + Пояснительная записка
Моделирование процесса обработки заданий пакетным режимом работы с квант...

Реклама



Подписывайся на YouTube канал о программировании, что бы не пропустить новые видео!

ПОДПИСЫВАЙСЯ на канал о программировании
Управление ресурсами и IUnknown



Как было в случае с DuplicatePointer и DestroyPointer из предыдущей главы, методы AddRef и Release из IUnknown имеют очень простой протокол, которого должны придерживаться все, кто пользуется указателями этих интерфейсов. Эти правила освобождают клиента от необходимости управлять временем жизни объекта, когда несколько интерфейсных указателей могут указывать или не указывать на один и тот же объект. Клиентам необходимо только следовать простым правилам AddRef/Release единообразно для всех интерфейсных указателей, с которыми им приходится сталкиваться, а объект будет сам управлять своим временем жизни.
Спецификация модели компонентных объектов (Component Object Model Specification) содержит четкие определения правил подсчета ссылок СОМ. Понимание мотивировки этих определений имеет решающее значение при СОМ-программировании на C++. Эти правила СОМ о подсчете ссылок могут быть сведены к трем простым аксиомам:
Когда ненулевой указатель интерфейса копируется из одной ячейки памяти в другую, должен вызываться AddRef для извещения объекта о дополнительной ссылке.
Перед тем как произойдет перезапись той ячейки памяти, где содержится ненулевой указатель интерфейса, необходимо вызвать Release , чтобы известить объект, что ссылка уничтожается.
Избыточное количество вызовов AddRef и Release можно сократить, если иметь дополнительную информацию о связях между двумя и более ячейками памяти.
Аксиома о дополнительной информации введена главным образом для того, чтобы ввести возможность преобразования запутанных ситуаций в разумные и осмысленные идиомы программирования (например, стеки временных вызовов и сгенерированное компилятором занесение переменной в регистр не нуждаются в подсчете ссылок). Можно провести месяцы в поиске особых связей между переменными, содержащими явные указатели на интерфейс в программе и оптимизировать избыточные вызовы AddRef и Release , но поступать так было бы неосмотрительно. Выгода от удаления этих избыточных вызовов явно незначительна, так как даже в худшем случае, когда объект вызывается с расстояния более 8500 миль со средней скоростью передачи 14.4 кбит/сек, эти избыточные вызовы никогда не уйдут из вызывающего потока и нечасто требуют множество инструкций для выполнения.
Если руководствоваться приведенными выше тремя простыми аксиомами о подсчете ссылок в интерфейсных указателях, то можно записать это в виде руководящих принципов программирования, чтобы установить, когда вызывать и когда не вызывать AddRef и Release . Вот несколько типичных ситуаций, требующих вызова метода AddRef :
А1. Когда ненулевой интерфейсный указатель записывается в локальную переменную.
А2. Когда вызываемый объект пишет ненулевой интерфейсный указатель в параметр [out] или [in, out] метода или функции.
A3. Когда вызываемый объект возвращает ненулевой интерфейсный указатель как физический результат (physical result) функции.
А4. Когда ненулевой интерфейсный указатель пишется в элемент данных объекта.
Некоторые типичные ситуации, требующие вызова метода Release :
R1. Перед перезаписью ненулевой локальной переменной или элемента данных.
R2. Перед тем как покинуть область действия ненулевой локальной переменной.
R3. Когда вызываемый объект перезаписывает параметр [in,out] метода или функции, начальное значение которых отлично от нуля. Заметим, что параметры [out] предполагаются нулевыми при вводе и никогда не могут освобождаться вызываемым объектом.
R4. Перед перезаписью ненулевого элемента данных объекта.
R5. Перед завершением работы деструктора объекта, имеющего в качестве элемента данных ненулевой интерфейсный указатель.
Типичная ситуация, к которой применимо правило о дополнительной информации, возникает при передаче указателей интерфейсов функциям как параметрам [in] :
S1. Когда при вызове функции или метода ненулевой интерфейсный указатель передается через [in] -параметр, вызов AddRef и Release , не требуются, так как время жизни временной переменной в стеке является строгим подмножеством времени жизни выражения, использованного для инициализации формального аргумента.
Эти десять руководящих принципов охватывают ситуации, снова и снова возникающие при программировании в СОМ, и было бы неплохо их запомнить.
Чтобы конкретизировать правила подсчета ссылок в СОМ, предположим, что имеется глобальная функция, которая возвращает объекту интерфейсный указатель:
void GetObject([out] IUnknown **ppUnk);
и что имеется другая глобальная функция, которая выполняет некую полезную работу над объектом:
void UseObject([in] IUnknown *pUnk);
Написанный ниже код использует эти процедуры, чтобы управлять некоторыми объектами и возвращать интерфейсный указатель вызывающему объекту. Руководящие принципы, применимые к каждому оператору, указаны в комментариях к нему:
void GetAndUse(/* [out] */ IUnknown ** ppUnkOut)
{ IUnknown *pUnk1 = 0, *pUnk2 = 0; *ppUnkOut =0;
// R3
// get pointers to one (or two) objects
// получаем указатели на один (или два) объекта
GetObject(&pUnk1);
//A2
GetObject(&pUnk2);
//A1
// set pUnk2 to point to first object
// устанавливаем pUnk2, чтобы указать на первый объект
if (pUnk2) pUnk2->Release():
//R1
if (pUnk2 = pUnk1) pUnk2->AddRef():
//A1
// pass pUnk2 to some other function
// передаем pUnk2 какой-нибудь другой функции
UseObject(pUnk2);
//S1
// return pUnk2 to caller using ppUnkOut parameter
// возвращаем pUnk2 вызывающему объекту, используя
// параметр ppUnkOut
if (*ppUnkOut = pUnk2) (*ppUnkOut)->AddRef();
// A2
// falling out of scope so clean up
// выходит за область действия и поэтому освобождаем
if (pUnk1) pUnkl->Release();
//R2
if (pUnk2) pUnk2->Release();
//R2
}



Важно отметить, что в вышеприведенном коде правило A2 применяется дважды, но по двум разным причинам. При вызове GetObject код выступает как вызывающий объект, а реализация GetObject является вызываемым объектом. Это означает, что реализация GetObject является ответственной за вызов AddRef через параметр [out] . При перезаписи памяти, на которую ссылается ppUnkOut , код выступает как вызываемый объект и корректно вызывает AddRef через интерфейсный указатель перед возвратом управления вызывающему объекту.
Существуют некоторые тонкости относительно AddRef и Release , подлежащие обсуждению. Как AddRef , так и Release предназначались для возврата 32-битного целого числа без знака. Это целое число отражает общее количество оставшихся ссылок после применения операций AddRef или Release . Однако по целому ряду причин, связанных с многопоточным режимом, удаленным доступом и мультипроцессорной архитектурой, нельзя быть уверенным в том, что эта величина будет точно отражать общее число неосвобожденных интерфейсных указателей, и клиенту следует игнорировать ее, если только она не используется в целях диагностики при отладке.
Единственный случай, заслуживающий внимания, это когда Release возвращает нуль. Нулевой результат от Release надежно свидетельствует о том, что данный объект более не действителен ни в каком смысле. Однако обратное неверно. Это значит, что когда Release возвращает не нуль, нельзя утверждать, что объект еще работоспособен. Фактически, если Release был вызван указателем интерфейса столько же раз, сколько этим же указателем интерфейса был вызван AddRef , то данный указатель интерфейса недействителен и более не обеспечивает указание на действующий объект. В то же время возможно, что это – случайность, а объект все еще работоспособен благодаря другим, еще не освобожденным, указателям, и все может измениться в самый неподходящий момент. Чтобы однажды освобожденные (released) интерфейсные указатели более не использовались, можно, например, обнулять их сразу же после вызова метода Release :
inline void SafeRelease(IUnknown * &rpUnk)
{
if (rpUnk)
{
rpUnk->Release();
rpUnk = 0;
// rpUnk passed by reference
// rpUnk, переданный ссылкой
}
}



Когда этот способ применен, любое использование указателя интерфейса после его высвобождения немедленно вызовет ошибку доступа. Эта ошибка затем может быть достоверно воспроизведена и, можно надеяться, отловлена еще на этапе разработки.
Еще одна тонкость, относящаяся к AddRef и Release , состоит в выходе из блока. Функция GetAndUse , приведенная ранее, имеет только одну точку выхода. Это означает, что операторы, высвобождающие указатели интерфейса в конце функции, будут всегда выполняться ранее завершения работы функции. Если же функция завершит работу, не доходя до этих операторов – либо благодаря явному оператору return или же, что хуже, необработанному (unhandled) исключению C++, – то эти завершающие операторы будут пропущены и все ресурсы, удерживаемые неосвобожденными интерфейсными указателями, будут утеряны до окончания клиентской программы. Это означает, что к указателям интерфейса СОМ следует относиться с осторожностью, особенно при использовании их в средах, использующих исключения C++. Впрочем, это касается и других системных ресурсов, с которыми приходится работать, будь то семафоры или динамически распределяемая память. Далее в этой главе обсуждаются интеллектуальные СОМ-указатели, которые обеспечивают вызов Release во всех ситуациях.
Опубликовал Kest July 13 2009 00:36:38 · 0 Комментариев · 4738 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Нет комментариев.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
EMSQuickImport
Plasma
Архив значков
Интерактивный инт...
Ранги для форума
TsHintManager
INSTANT BOOSTER v...
Просмотр коммент...
Алгоритм трассиро...
Форма в форме
VksButton
AntiRus
Библия хакера 2. ...
Cooltray
XPATComponents
Просмотр файлов и...
Srinilist
Sztransppanel
Игра змейка
Библия хакера 2 К...

Топ загрузок
Приложение Клие... 100371
Delphi 7 Enterp... 82700
Converter AMR<-... 20046
Borland C++Buil... 11125
GPSS World Stud... 10655
Borland Delphi ... 8080
Turbo Pascal fo... 6967
Visual Studio 2... 4963
Калькулятор [Ис... 4307
FreeSMS v1.3.1 3510
Случайные статьи
Этап 1 - исключени...
— закрытый ключ 80...
Семантический анал...
Групповые адреса T...
Создание объекта D...
Процедуры обработк...
Constant and саsе ...
РЕЖИМ "ПОПОЛНЕНИЕ ...
HR. Старайтесь исп...
Игра ОлдБК Mmorpg.
Тестирование, поис...
Выделение трех объ...
Упорядочивание по ...
Принципы взаимодей...
Средства отладки -...
Модели выполнения ...
Организация информ...
Добавление и удале...
Флаги сообщений BP...
Вопросы руководств...
Шаблоны и наследов...
Читателям первого ...
Задача реализации ...
Клонирование в STR...
Применение асиммет...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?