使用CComSafeArray <bstr>时为什么要泄漏内存?

时间:2015-07-23 10:29:20

标签: c++ com

我有内存泄漏,我已经缩小到以下代码。发生了什么事?

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;
}

1 个答案:

答案 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;
    }
};