zar
zar

Reputation: 12237

How to clean up _variant_t

My leak checker tells me there is 2nd chance exception in this function.

BOOL CADORecordset::SetFieldValue(LPCTSTR lpFieldName, CString strValue)
{
    _variant_t vtFld;

    if(!strValue.IsEmpty())
        vtFld.vt = VT_BSTR;
    else
        vtFld.vt = VT_NULL;

    vtFld.bstrVal = strValue.AllocSysString();

    BOOL bret = PutFieldValue(lpFieldName, vtFld);
    SysFreeString(vtFld.bstrVal);

    return bret;
}

Now _variant_t has a type BSTR member (bstrVal). We know that BSTR needs to be de-allocated using SystemFreeString() which is what is done in the code above but since this BSTR is member of _variant_t who has its own destructor which cleans up, who should really clean up the bstrVal member in this case?

inline _variant_t::~_variant_t() throw()
{
    ::VariantClear(this);
}

It appears to me that this tries to clean up the memory again which is already cleaned up by SysFreeString() causing the exception? The documentation says it clears the variant but it is not clear what exactly it clears, does it free up the bstrVal as well?

If I remove the call SysFreeString(vtFld.bstrVal); this does remove the 2nd chance exception but I really want to know that's the right thing to do because the documentation doesn't give enough confidence.

Upvotes: 0

Views: 2463

Answers (2)

monkeyman79
monkeyman79

Reputation: 632

variant_t owns its data and uses the VariantClear() function for cleanup:

The function clears a VARIANTARG by setting the vt field to VT_EMPTY. The current contents of the VARIANTARG are released first. If the vtfield is VT_BSTR, the string is freed. If the vtfield is VT_DISPATCH, the object is released. If the vt field has the VT_ARRAY bit set, the array is freed.

_variant_t is a wrapper which takes care of memory management. Similar to _bstr_t, which manages a BSTR; they work best together. Instead of manually setting the vt field and the bstrVal value, it's better to use the variant_t constructor or operator=. _bstr_t will allocate and pass BSTR ownership to _variant_t. I don't remember the details of using it. Just look up the details on MSDN.

Upvotes: 2

Remy Lebeau
Remy Lebeau

Reputation: 596998

_variant_t automatically cleans up its data when it goes out of scope. You are manually calling SysFreeString(), but you are not setting bstrVal to NULL or setting vt to VT_EMPTY afterwards. So, when the variant_t destructor calls VariantClear() to clean up the data, it tries to free the bstrVal again and crashes.

So, simply do not call SysFreeString() manually at all. If you ever need to reset a variant_t manually, use its Clear() method instead:

vtFld.Clear();

Upvotes: 5

Related Questions