c++ - 使用 COM 进行异常安全的内存处理

标签 c++ com atl smart-pointers

使用 COM 时,我通常依赖 ATL 智能指针,如 ATL::CComPtrATL::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 提供的某些内容?

最佳答案

ATL 已经有这个开箱即用:

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

CHeapPtr 可以派生以类似的方式实现其他资源释放器。 CComHeapPtr 是一个 MSDN documented class .

关于c++ - 使用 COM 进行异常安全的内存处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15419669/

相关文章:

c++ - 为什么 c++ 使用 CustomClass** 而不是 CustomClass* 来创建返回 CustomClass 指针列表的函数?

c++ - 如何在 COM/ATL 项目中使用 DATE 类型

c++ - 从模式对话框中抛出异常的最佳做法是什么?

c++ - 尝试使用 DDX_CONTROL 连接控件时出错

c++ - 可以报​​告哪些类型的误报内存泄漏?

c++ - 我们如何从成员函数返回一个 unique_pointer 成员?

c++ - 在工作 GUI 示例中使用 Controller 和 QT Worker

c++ - 我可以阻止 COM 在被调用进程中吞下未捕获的 C++ 异常吗?

c# - 哪一个是错误的? Msdn 或头文件

windows - MFC .dll 调试断言