10

COMを使用する場合、私は通常、リソース管理にATL::CComPtrandなどのATLスマートポインターを使用します。ATL::CComBSTRしかし、私が呼び出しているメソッドのいくつかは、出力パラメーターを使用して、解放する必要のある割り当てられたストレージへのポインターを返します。例えば:

WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
  DoSomething(pszName);
  CoTaskMemFree(pszName);
}

GetDisplayName文字列にメモリを割り当て、出力パラメータを介して文字列へのポインタを返すことに注意してください。でそのメモリを解放するのは、呼び出し元の責任CoTaskMemFreeです。

DoSomething例外をスローすると、上記のコードがリークします。pszNameこのようなリークを回避するために、ある種のスマートポインターを使用したいのですが、APIが必要なWCHAR**ので、ダムポインターのアドレス以外を渡す方法がわかりません。割り当てているのは私ではないので、RAIIは使えません。

次のような削除機能を作成できる場合は、RRIDを使用できます。

struct CoTaskMemDeleter {
  void operator()(void *p) { ::CoTaskMemFree(p); }
};

そして、返されたポインタを次のような標準のスマートポインタにすぐに割り当てます。

WCHAR *pszName = nullptr;
if (SUCCEEDED(pShellItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName))) {
  std::unique_ptr<WCHAR, CoTaskMemDeleter> guard(pszName);
  DoSomething(pszName);
}

それは機能しますが、追加のガード変数を導入するとエラーが発生しやすいようです。たとえば、このアプローチpszNameでは解放されたメモリをポイントしたままになるため、誤って再度使用する可能性があります。

出力パラメータによって返されるCOMサーバーに割り当てられたメモリにスマートポインタまたはRAIIラッパーを使用するよりクリーンな方法はありますか?ATLが提供するものが欠けていますか?

4

1 に答える 1

14

ATLには、すぐに使用できるものがあります。

CComHeapPtr<WCHAR> pszName;
const HRESULT nResult = pShellItem->GetDisplayName(..., &pszName);
// Hooray, pszName will be CoTaskMemFree'd for you on scope leave 
// via ~CComHeapPtr

CHeapPtr同様の方法で他のリソースリリーサーを実装するように導出できます。MSDNで文書化されCComHeapPtrたクラスです。

于 2013-03-14T21:01:05.463 に答える