考虑以下代码,这是否存在内存泄漏?
topHeadSink
这有什么不同?(仍然是内存泄漏?)
val g = RunnableGraph.fromGraph(GraphDSL.create(topHeadSink, bottomHeadSink)((t, _) => t) {
implicit builder => (topHS, bottomHS) =>
...
}).run() // Future[Int]
答案 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
,并在其上调用SysFreeString
? std::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。
此外,我鼓励您阅读这篇有趣的博客文章: