Есть ли утечка памяти при вызове CComPtr и QueryInterface?
Подскажите, этот код имеет право на существование или нет?
HRESULT CMyClass::Assign(IUnknown * src) {
if (!src)
return E_INVALIDARG;
HRESULT res;
ATL::CComPtr<IAddress> addr;
res = src->QueryInterface<IAddress>(&addr);
if (SUCCEEDED(res))
return addr->getStreet(*this->street);
else
return res;
}
Что меня смущает. В конструкторе класса CBasePtr, который является родительским классом для класса CComPtr, я вижу вызов AddRef(). Но QueryInterface, по идее уже сам вызывает AddRef(), т.е. получится утечка памяти. Или т.к. в QueryInterface передается указатель, то дополнительный AddRef() вызываться не будет?
Ответы (1 шт):
Базовым классом для CComPtr у меня в VS2017 является CComPtrBase. Вот его конструкторы (из atlcomcli.h):
CComPtrBase() throw()
{
p = NULL;
}
CComPtrBase(_Inout_opt_ T* lp) throw()
{
p = lp;
if (p != NULL)
p->AddRef();
}
Как видно, здесь есть вызов AddRef, но только в конструкторе с параметром. Этот конструктор вызывался бы в коде вида ATL::CComPtr<IAddress> addr(somePointer);. В вашем случае же вызывается конструктор без параметра, а затем в пустой экземпляр CComPtr записывается адрес из QueryInterface. AddRef будет вызван только один раз (в QueryInterface).
Сказать, есть ли утечка памяти, по приведенному неполному коду нельзя. Если в метод передается правильная реализация IUnknown, то ее не должно быть, в том смысле, что в этом коде нечему вызвать утечку памяти. Есть ли утечка памяти в вашем реальном коде можно узнать с помощью отладчика, поставив точку останова на метод Release в COM-объекте. Если все нормально, при последнем вызове Release счетчик ссылок должен быть равен нулю.