Существуют некоторые тонкости относительно
Единственный случай, заслуживающий внимания, это когда
inline void SafeRelease(IUnknown * &rpUnk)
{
if (rpUnk)
{
rpUnk->Release;
rpUnk = 0;
// rpUnk passed by reference
// rpUnk, переданный ссылкой
}
}
Когда этот способ применен, любое использование указателя интерфейса после его высвобождения немедленно вызовет ошибку доступа. Эта ошибка затем может быть достоверно воспроизведена и, можно надеяться, отловлена еще на этапе разработки.
Еще одна тонкость, относящаяся к
Приведение типов и IUnknown
В предыдущей главе обсуждалось, почему необходимо определять тип на этапе выполнения в динамически собранной системе. Язык C++ предусматривает разумный механизм для динамического определения типа с помощью оператора dynamic_cast. Хотя эта языковая возможность имеет собственную реализацию для каждого компилятора, в предыдущей главе было предложено средство урегулирования этого – добавление к каждому интерфейсу явного метода, являющегося семантическим эквивалентом dynamic_cast. Ниже приводится IDL-описание QueryInterface:
HRESULT QueryInterface([in] REFIID riid, [out] void **ppv);
Первый параметр (riid) является физическим именем запрошенного интерфейса. Второй параметр (ppv) указывает на переменную интерфейсного указателя, которая в случае успешного завершения будет содержать запрошенный указатель на интерфейс.
В ответ на запрос QueryInterface, если объект не поддерживает запрошенный тип интерфейса, он должен возвратить E_NOINTERFACE после установки *ppv в нулевое значение. Если же объект поддерживает запрошенный интерфейс, он должен перезаписать *ppv указателем запрошенного типа и возвратить HRESULT S_OK. Поскольку ppv является [out]-параметром, реализация QueryInterface должна выполнить AddRef для возвращаемого указателя перед тем, как вернуть управление вызывающему объекту (см. в этой главе выше руководящий принцип А2). Этот вызов AddRef должен быть согласован с вызовом Release со стороны клиента. Следующий код показывает динамическое определение типа с использованием оператора C++ dynamic_cast на примере иерархии типов Dog/Cat, описанного ранее в данной главе:
void TryToSnoreAndIgnore(/* [in] */ IUnknown *pUnk)
{
IPug *pPug = 0;
pPug = dynamic_cast
if (pPug)
// the object is Pug-compatible
// объект совместим с Pug
pPug->Snore;
ICat *pCat = 0;
pCat = dynamic_cast
if (pCat)
// the object is Cat-compatible
// объект совместим с Cat
pCat->IgnoreMaster;
}