Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception-safe memory handling with COM

When using COM, I typically rely on ATL smart pointers, like ATL::CComPtr and ATL::CComBSTR, for resource management. But some of the methods I'm calling use output parameters to return pointers to allocated storage that I have to free. For example:

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

Note that GetDisplayName allocates memory for the string and returns a pointer to it through the output parameter. It's the caller's responsibility to free that memory with CoTaskMemFree.

If DoSomething throws an exception, then the above code will leak. I'd like to use some sort of smart pointer for pszName to avoid such leaks, but the API takes WCHAR**, so I don't see how I can pass anything but the address of a dumb pointer. Since I'm not the one allocating, I can't use RAII.

I can use RRID if I can make a deleter like this:

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

And then immediately assign the returned pointer to a standard smart pointer like this:

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

That works, but it seems error-prone to introduce an extra guard variable. For example, this approach leaves pszName pointing at the released memory, so it would be easy to accidentally use it again.

Is there a cleaner way to use a smart pointer or an RAII wrapper for COM-server allocated memory returned by output parameter? Am I missing something that ATL provides?

like image 905
Adrian McCarthy Avatar asked Mar 14 '13 20:03

Adrian McCarthy


1 Answers

ATL already has this one out of the box:

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

CHeapPtr can be derived to implement other resource releasers in a similar way. CComHeapPtr is a MSDN documented class .

like image 149
Roman R. Avatar answered Oct 17 '22 15:10

Roman R.