BSTR中的内存泄漏为wstring

时间:2018-02-06 16:16:58

标签: c++ memory-leaks com bstr

考虑以下代码,这是否存在内存泄漏?

topHeadSink

这有什么不同?(仍然是内存泄漏?)

val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, _) => t) {
  implicit builder => (topHS, bottomHS) =>
  ...
}).run() // Future[Int]

1 个答案:

答案 0 :(得分:4)

CComBSTR是原始BSTR字符串的RAII包装器。

在您发布的第一个代码段中:

outDomainPath = bstrDomainPath.Detach();

您调用CComBSTR::Detach释放已包装的BSTR字符串的所有权此所有权转移到"其他人& #34 ;.
在你的情况下,"其他人"是std::wstring对象(由outDomainPath引用),它是围绕BSTR的RAII包装器。

现在,请考虑一下,从C ++类型系统的角度来看,BSTR基本上是wchar_t*。此外,std::wstring实现了以const wchar_t*为输入的构造函数和赋值运算符重载,假设这些原始wchar_t指针是C风格的NUL终止字符串。因此,您可以从原始C风格的字符串创建std::wstring个对象。

问题在于,当您调用CComBSTR::Detach时,原始BSTR所有权将转移给调用方,调用方负责正确发布 BSTR字符串。

但是,在您的情况下,您要从wstring" orphaning&#返回的wchar_t*BSTR)创建CComBSTR::Detach个对象34; 返回的BSTR字符串。

事实上,谁将负责正确发布BSTR,并在其上调用SysFreeStringstd::wstring析构函数不会这样做。

因此,在这种情况下,您会泄漏BSTR返回的CComBSTR::Detach

另一方面,在第二个代码片段中:

outDomainPath = bstrDomainPath;//removed detach

发生的事情是编译器隐式调用CComBSTR::operator BSTR,这基本上允许调用者访问BSTR内部CComBSTR。请注意,在这种情况下,没有所有权转移:您只是观察 BSTR,它仍由CComBSTR RAII包装器拥有。

std::wstring具有构造函数和op =重载以从原始wstring NUL终止的C样式字符串创建const wchar_t*个对象。 BSTR基本上是来自C ++类型系统视角的wchar_t*,所以如果你的BSTR包含一个以NUL结尾的字符串(没有嵌入的NULs),那么代码将复制 BSTR字符串,并将其复制到std::wstring对象。

然后,在GetPath函数的末尾,本地CComBSTR bstrDomainPath对象将超出范围,C ++编译器将自动调用CComBSTR析构函数,并{{将调用1}}以正确释放包裹的SysFreeString

在这种情况下,您没有BSTR泄漏。

请注意,如果您没有在您的BSTR中嵌入了NUL,则此代码有效。对于嵌入式NUL,只会复制第一个"子串" ,因为BSTR作为输入的wstring构造函数将停止在首先 NUL。

此外,我鼓励您阅读这篇有趣的博客文章:

  

Eric Lippert's Guide to BSTR Semantics