snb*_*snb 1 c++ com memory-leaks bstr
考虑以下代码,这是否存在内存泄漏?
HRESULT GetPath(wstring &outDomainPath)
{
CComBSTR bstrDomainPath;
AnotherGetPath(&bstrDomainPath);
outDomainPath = bstrDomainPath.Detach();
}
Run Code Online (Sandbox Code Playgroud)
这有什么区别?(还是内存泄漏??)
HRESULT GetPath(wstring &outDomainPath)
{
CComBSTR bstrDomainPath;
AnotherGetPath(&bstrDomainPath);
outDomainPath = bstrDomainPath;//removed detach
}
Run Code Online (Sandbox Code Playgroud)
CComBSTR是围绕原始BSTR字符串的 RAII 包装器。
在您发布的第一个代码片段中:
Run Code Online (Sandbox Code Playgroud)outDomainPath = bstrDomainPath.Detach();
您调用CComBSTR::Detach,它释放包装BSTR字符串的所有权,并将此所有权转移给“其他人”。
在您的情况下,“其他人”是一个std::wstring对象(由 引用outDomainPath),它不是围绕BSTRs的 RAII 包装器。
现在,考虑一下,从 C++ 类型系统的角度来看, aBSTR基本上是 a wchar_t*。此外,假设这些原始指针是 C 风格的 NUL 终止字符串,std::wstring实现const wchar_t*作为输入的构造函数和赋值运算符重载wchar_t。因此,您可以std::wstring从原始 C 样式字符串创建对象。
问题是,当你调用CComBSTR::Detach,原BSTR所有权转移给调用者,负责妥善释放的BSTR字符串。
但是,在您的情况下,您正在wstring从wchar_t*( BSTR) 返回的对象创建一个对象CComBSTR::Detach,“孤立”返回的BSTR字符串。
事实上,谁将负责正确释放BSTR, 调用SysFreeString它?该std::wstring析构函数不会那么做的。
所以,在这种情况下,您泄漏了BSTR由返回CComBSTR::Detach。
另一方面,在第二个代码片段中:
Run Code Online (Sandbox Code Playgroud)outDomainPath = bstrDomainPath;//removed detach
发生的情况是编译器隐式调用CComBSTR::operator BSTR,这基本上使调用者可以访问BSTR包装在里面的CComBSTR. 请注意,在这种情况下,有没有所有权的转移:你只是观察到的BSTR,这仍然是由拥有CComBSTRRAII包装。
std::wstring具有构造函数和 op= 重载以wstring从原始的const wchar_t*NUL 终止的 C 样式字符串创建对象。BSTR基本上是wchar_t*从 C++ 类型系统的角度来看,因此如果您BSTR包含以 NUL 结尾的字符串(内部没有嵌入的 NUL ),则该行代码将复制该BSTR字符串,将其复制到一个std::wstring对象中。
然后,在您的GetPath函数结束时,本地CComBSTR bstrDomainPath对象将超出范围,CComBSTR析构函数将被 C++ 编译器自动调用,SysFreeString并将被调用以正确释放包装的BSTR.
在这种情况下,您没有BSTR泄漏。
请注意,此代码的工作,如果你不已经在你的嵌入式完全无效BSTR。在嵌入NUL 的情况下,只会复制第一个“子字符串”,因为wstring将 aconst wchar_t*作为输入的构造函数将在第一个NUL处停止。
此外,我鼓励您阅读这篇有趣的博客文章: