我有内存泄漏,我已经缩小到以下代码。发生了什么事?
CComSafeArray<BSTR> sa(5);
sa[0] = SysAllocString("constant");
CComSafeArray::~CComSafeArray
来电SafeArrayDestroy
(通过CComSafeArray::Destroy()
,见下文),所有成员should then call SysFreeString
。因此,这里不应该是泄漏。发生了什么事?
HRESULT Destroy()
{
HRESULT hRes = S_OK;
if (m_psa != NULL)
{
hRes = Unlock();
if (SUCCEEDED(hRes))
{
hRes = SafeArrayDestroy(m_psa);
if (SUCCEEDED(hRes))
m_psa = NULL;
}
}
return hRes;
}
答案 0 :(得分:3)
简答:
而不是在CComSafeArray<BSTR>
中保存指针的副本,CComSafeArray<BSTR>::operator[]
和CComSafeArray<BSTR>::GetAt(T)
会返回一个CComBSTR
对象,该对象会获取BSTR
的副本。这会导致BSTR
泄漏。
答案很长:
经过几个无效的工作时间,在尝试编译更简单的版本以尝试缩小泄漏范围时出现编译错误,导致其失败:
CComSafeArray<BSTR> sa(5);
sa[0] = nullptr;
这不会编译,因为在封面CComSafeArray<BSTR>::operator[]
下会返回CComBSTR
个对象,nullptr
可以匹配CComBSTR::operator=(LPCSTR)
和CComBSTR::operator=(LPCOLESTR)
。 Bam,编译错误。
一旦我发现CComBSTR
涉及到封面,它就会落到实处。 CComBSTR::operator=
takes a copy of the BSTR
instead of saving the pointer(我如何阅读代码,给定正常行为)或取得所有权,导致不同意的临时BSTR
泄露。
typename _ATL_AutomationType<T>::_typewrapper& GetAt(_In_ LONG lIndex) { ... }
...
// specialization for BSTR so GetT doesn't return &BSTR
template <>
struct _ATL_AutomationType<BSTR>
{
typedef CComBSTR _typewrapper ;
enum { type = VT_BSTR };
static void* GetT(_In_ const BSTR& t) throw()
{
return t;
}
};