zar zar - 3 months ago 28
C++ Question

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.

Answer

_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();