Search code examples
comvariantsafearrayole-automation

Proper cleanup of CComSafeArray<VARIANT>


Given:

{
    CComSafeArray<VARIANT> sa;
    CComVariant ccv(L"test");
    sa.Add(ccv, TRUE);
}

I was hoping the dtor of CComSafeArray would call ::VariantClear on each contained member and the documentation seems to indicate that:

In certain cases, it may be preferable to clear a variant in code without calling VariantClear. For example, you can change the type of a VT_I4 variant to another type without calling this function. Safearrays of BSTR will have SysFreeString called on each element not VariantClear. However, you must call VariantClear if a VT_type is received but cannot be handled. Safearrays of variant will also have VariantClear called on each member.

(source: http://msdn.microsoft.com/en-us/library/windows/desktop/ms221165(v=vs.85).aspx)

But I see no such thing happening in the code in atlsafe.h.

Am I just looking in the wrong place or is this just supposed to happen as a side-effect of ::SafeArrayDestroy() -- which is the only thing happening via the CComSafeArray dtor.


Solution

  • Ultimately VariantClear will get called on the contents of the CComSafeArray object, albeit after progressing through multiple layers. CComSafeArray::~CComSafeArray() calls CComSafeArray::Destroy() which is ultimately a wrapper of SafeArrayDestroy():

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

    SafeArrayDestroy() is documented as calling VariantClear on its contents if it contains VARIANTs:

    Safe arrays of variant will have the VariantClear function called on each member and safe arrays of BSTR will have the SysFreeString function called on each element.