Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

62

Правило для параметров типа вход-выход

Параметр типа вход-выход (in-out parameter) может одновременно быть и входным, и выходным. Функция использует переданное ей значение такого параметра, затем изменяет его и возвращает вызывающей программе.

Функция обязана вызвать Release для указателя на интерфейс, переданного ей как произвольный параметр, прежде чем записать на его место новый указатель. Перед возвратом в вызывающую программу функция также должна вызвать AddRef для нового значения параметра.

void ExchangeForChangedPtr(int i, IX** ppIX)

{

(**ppIX)->Fx();

// Делаем

что-нибудь

с

входным параметром

(**ppIX)->Release();

// Освобождаем входной

параметр

*ppIX = g_Cache[i];

// Выбираем

указатель из кэша

(**ppIX)->AddRef();

// Вызываем

для него

AddRef

(**ppIX)->Fx();

// Делаем

что-нибудь

с

выходным параметром

}

Правило для локальных переменных

Локальные копии указателей на интерфейсы, конечно, существуют только во время выполнения функций и не требуют пар AddRef / Release. Это правило непосредственно вытекает из правила для входных параметров. В приведенном далее примере pIX2 гарантированно будет существовать только во время выполнения функции foo. Таким образом, его существование вложено во время жизни указателя pIX, переданного как входной параметр, — так что вызывать AddRef или Release для pIX2 не нужно.

void foo(IX* pIX)

{

IX* pIX2 = pIX; pIX2->Fx();

}

Правило для глобальных переменных

Если указатель на интерфейс сохраняется в глобальной переменной, то прежде чем передавать управление другой функции, необходимо вызвать AddRef. Поскольку переменная является глобальной, любая функция может вызвать Release и закончить жизнь этого указателя. Указатели на интерфейсы, сохраняемые в переменныхчленах, должны обрабатываться аналогично. Любая функция-член класса может изменить состояние такого указателя.

Правило для сомнительных случаев

Всякий раз, когда у Вас возникает сомнение, вставляйте пару AddRef / Release. Ее отсутствие редко дает значительный выигрыш в производительности или экономию памяти, зато легко может привести к созданию компонента, который никогда не удаляется из памяти. Кроме того, Вы можете потратить много времени на поиск ошибки, вызванной неправильным подсчетом ссылок. Как обычно, с помощью профилировщика можно определить, дает ли оптимизация существенный выигрыш. Помимо этого, если Вы все же решили применить оптимизацию, обязательно пометьте указатель, для которого не выполняется подсчет ссылок, соответствующим комментарием. Другому программисту, модифицирующему Ваш код, очень легко запутаться во временах жизни и нарушить правильность оптимизированного подсчета ссылок.

Пропущенный вызов Release труднее обнаружить, чем отсутствие вызова AddRef. Программисты на С++ легко могут забыть вызвать Release или, еще хуже, попытаться использовать delete вместо Release. В гл. 10 показано, как smart-указатели могут полностью инкапсулировать подсчет ссылок.

Амуниция пожарного, резюме

Методы IUnknown дают нам полный контроль над интерфейсами. Как мы видели в предыдущей главе, указатели на интерфейсы, поддерживаемые компонентом, можно получить через QueryInterface. В этой главе мы видели, как AddRef и Release управляют временами жизни полученных интерфейсов. AddRef сообщает компоненту, что мы собираемся использовать интерфейс. Release сообщает, что использование интерфейса закончено. Release также предоставляет компоненту некоторую способность управлять своим временем жизни. Клиент никогда не выгружает компонент напрямую; вместо этого Release сигнализирует, что клиент завершил работу с интерфейсом. Если ни один из интерфейсов никем не используется, компонент может удалить себя сам.

Хотя теперь мы имеем все возможности управления интерфейсами, у нас нет одной важной составляющей компонентной архитектуры — динамической компоновки. Компонент без динамической компоновки — это все

63

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

Соседние файлы в предмете Программирование на C++