Сущность технологии СОМ. Библиотека программиста | страница 51



-параметр, вызов 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-битного целого числа без знака. Это целое число отражает общее количество оставшихся ссылок