COM 자동 초기화와 자동 클린업
CComPtr 인스턴스를 사용하는 COM 코드가 다음과 같다고 하자.
{
HRESULT hr = CoInitialize(NULL);
// 반환값 확인.
CComPtr<ISomeInterface> sp1;
CComPtr<IAnotherInterface> sp2;
// 인터페이스 포인터로 작업
CoUninitialize();
}
이 코드에는 미묘한 버그가 있다. 문제는 CoUninitialize 가 CComPtr 파괴자 전에 실행된다는 점이다. 옳바른 방법은 CoUninitialize 가 모든 COM 인터페이스 포인터가 (자신의 래핑된 CComPtr 파괴자에서) 릴리즈 된 이후에 와야한다.
그리고 여기엔 예외 안전성 문제도 있다. 코드블럭 중간에 어떤 예외가 던져진다(발생한다)면, CoUninitialize 함수는
불리지 않게 된다.
이 두가지 문제를 해결하기 위해, RAII 패턴을 따르는 C++ 클래스를 정의할 수 있다. 이 클래스의 생성자는 CoInitialize 를 호출하고, 초기화가 실패하면 예외를 던진다. 클래스의 파괴자는 CoUninitialize 를 호출한다. 따라서 모든 성공한 CoInitialize 호출은 (COM 프로그래밍 법칙이 요구하는 대로) 대응되는 CoUninitialize 을 갖게 된다.
나아가, 클래스 인스턴스가 스택에 생성되고, CComPtr (를 비롯한 COM 스마트 포인터들) 보다앞에 있다고 하면, oUninitialize 는 모든 CComPtr의 파괴자가 호출된 뒤에 마지막에 불리게 될 것이다.
{
// COM 자동 초기화와 자동 정리
CComAutoInit comInit;
CComPtr<ISomeInterface> sp1;
CComPtr<IAnotherInterface> sp2;
// 인터페이스 포인터로 작업
}
CComAutoInit 클래스의 완전한 코드는 원본 블로그포스트에 첨부되어 있다. (고 하는데 없더라.) 더불어 몇가지 부가적인 세부사항이 있다. 프라이빗 복사생성자와 =연산자가 정의되어 있어서, 이 클래스의 깊은복사를 막아 놓았다.
그리고, CComAutoInit 생성자의 익스플리싯 오버로드가 DWORD 인자를 받고, 이것은 CoInitializeEx 의 dwCoInit 인자로 쓰인다.
CComAuthInit 클래스를 어떻게 사용하는지를 보여주는 예제소스가 원본 블로그포스트에 첨부되어 있다. (고 하는데 없다.) 예제는 커맨드라인 인자로 주어진 단어를 "읽는" 예제 이다. (조금 더 복잡한 GUI MFC 버전은 MSDN Code Gallery 에서 찾을 수 있다.)
'프로그래밍 > C-CPP' 카테고리의 다른 글
[VS] LINK : warning LNK4075: '/INCREMENTAL'이(가) '/LTCG' 사양으로 인해 무시됩니다. (0) | 2016.09.30 |
---|---|
DWORD PTR fs:[0] 는 무엇인가? (0) | 2016.02.19 |
[SO번역] zlib: `deflate` 함수와 `compress` 함수의 차이점은 (1) | 2015.12.24 |
CPP/STL const map 객체에 [key] 접근시 에러 (1) | 2015.11.20 |
[CPP] 포인터인자와 레퍼런스인자 함수 생성 asm 비교. (2) | 2015.08.05 |