2010-01-15 3 views
4

나는 개체를 반환하는 방법으로 COM 인터페이스가 :작성할 수없는 COM 개체에 대한 참조 카운터를 더 잘 초기화하는 방법은 무엇입니까?

interface ICreatorInterface { 
    HRESULT CreateObject(IObjectToCreate**); 
}; 

의 핵심은 ICreatorInterface::CreateObject()를 호출하면 IObjectToCreate 인터페이스를 구현하는 객체를 검색 할 수있는 유일한 방법이라는 것이다.

HRESULT CCreatorInterfaceImpl::CreateObject(IObjectToCreate** result) 
{ 
    //CObjectToCreateImpl constructor sets reference count to 0 
    CObjectToCreateImpl* newObject = new CObjectToCreateImpl(); 
    HRESULT hr = newObject->QueryInterface(__uuidof(IObjectToCreate), (void**)result); 
    if(FAILED(hr)) { 
     delete newObject; 
    } 
    return hr; 
} 

또는 경우에

HRESULT CCreatorInterfaceImpl::CreateObject(IObjectToCreate** result) 
{ 
    //CObjectToCreateImpl constructor sets reference count to 1 
    CObjectToCreateImpl* newObject = new CObjectToCreateImpl(); 
    HRESULT hr = newObject->QueryInterface(__uuidof(IObjectToCreate), (void**)result); 
    // if QI() failed reference count is still 1 so this will delete the object 
    newObject->Release(); 
    return hr; 
} 

의 차이는 개체 삭제를 구현하는 방법을 참조 카운터가 초기화되고 어떻게이 QueryInterface() 실패 이러한 방법 : 나는 이런 식으로 할 수있는 C에서

++ . CCreatorInterfaceImplCObjectToCreateImpl을 완전히 제어 할 수 있으므로 두 가지 방법 중 하나를 선택할 수 있습니다.

IMO 첫 번째 변형이 더 명확합니다. 모든 참조 계산 항목은 코드 한 조각에 있습니다. 내가 뭔가를 봤어? 왜 두 번째 접근법이 더 좋을까요? 위의 어느 것이 더 낫고 왜?

답변

3

모두 변화가

  • 는 0의 심판이 카운트를 갖는 COM 객체에 AddRef에 이외의 다른 방법을 호출 절대로 COM

    의 아주 기본 원칙을 위반.

그렇지 않으면 모든 종류의 오류가 발생합니다. 사람들이 물체에 대한 완전한 법적 조작을 수행 할 수 없기 때문에 간단히 입력하십시오. 스마트 포인터에 넣는 것. 스마트 포인터는 AddRef를 호출하고 카운트를 1로 설정 한 다음 Release를 0으로 설정하고 객체를 자체 파괴시킵니다.

예 저는 QueryInterface 구현의 90 %가이 작업을 수행하지 않는다는 것을 알고 있습니다. 그러나 나는 또한 거기에 몇 가지가 있다는 것을 보장한다.

가장 간단한 접근법은 객체를 생성 한 직후에 AddRef를 호출하는 것이다. 이렇게하면 개체가 가능한 한 빨리 일반적인 COM 개체처럼 동작 할 수 있습니다.

나는 과거에이 문제에 부딪 혔고 나는 (객체가 ATL로 구현되었다고 가정 할 때) 멋진 작은 도우미 메서드를 작성했다.

template <class T> 
static 
HRESULT CreateWithRef(T** ppObject) 
{ 
    CComObject<T> *pObject; 
    HRESULT hr = CComObject<T>::CreateInstance(&pObject); 
    if (SUCCEEDED(hr)) 
    { 
     pObject->AddRef(); 
     *ppObject = pObject; 
    } 

    return hr; 
} 
+0

나는 당신의 점을 볼 수 있지만, 바로 그 동작은 훨씬 더 간단 달성 할 수있다 : 생성자에서 0 refcount가 init을 문제의 코드에 스마트 포인터를 사용 - 바로 스마트로 new'ed 객체를 바인딩 포인터를 누른 다음 QI() 호출 - ATL :: CComPtr 허용, 아마도 _com_ptr_t 너무 있습니다. – sharptooth

0

난 항상 메모리 문제를 방지하기 위해 반환 COM 개체를 만들기 위해 다음 코드 시나리오를 사용합니다. 물론이 작업은 내 개체가 참조 카운트 = 0이므로 만들어집니다. 이것은 항상 삭제 연산자를 사용하여 오류 조건을 처리하려고 시도하는 것보다 분명하게 보인다.

HRESULT CCreatorInterfaceImpl::CreateObject(IObjectToCreate** result) 
{ 
    //CObjectToCreateImpl constructor sets reference count to 0 
    CObjectToCreateImpl* newObject = new CObjectToCreateImpl(); 

    newObject->AddRef(); 

    HRESULT hr = newObject->QueryInterface(__uuidof(IObjectToCreate), (void**)result); 

    newObject->Release(); // release my addref, if QI succeeded it AddRef'd, if not the object is destroyed 

    return hr; // return result from QI 
} 
+1

CComPtr과 같은 스마트 포인터를 사용하면 두 번 적은 코드로 동일한 효과를 얻을 수 있습니다. – sharptooth

+0

사실, 사소한 문제는 코드에서 객체에 대한 비 인터페이스 기반 메소드를 호출해야하는 경우 (내부 초기화 - 잠재적 오류 상황으로 인해 생성자에서 처리되지 않았을 것 같은) 또는) 인터페이스보다는 적절한 유형에 대한 포인터가 필요합니다. – Ruddy

+0

대부분의 경우 CComPtr은 인터페이스가 아닌 실제 파생 된 유형으로 매개 변수화 할 수 있습니다. – sharptooth

관련 문제