如何清理 _variant_t

How to clean up _variant_t

我的泄漏检查器告诉我这个函数中有第二次机会异常。

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

现在 _variant_t 有一个类型为 BSTR 的成员 (bstrVal)。我们 know BSTR 需要使用 SystemFreeString() 取消分配,这是在上面的代码中完成的,但由于此 BSTR 是 _variant_t 的成员,它有自己的析构函数来清理,在这种情况下,谁应该真正清理 bstrVal 成员?

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

在我看来,这似乎试图再次清理已经被 SysFreeString() 清理的内存,导致异常? documentation 说它清除了变体,但不清楚它到底清除了什么,它是否也释放了 bstrVal

如果我删除调用 SysFreeString(vtFld.bstrVal); 这确实会删除第二次机会异常,但我真的想知道这是正确的做法,因为文档没有提供足够的信心。

variant_t owns its data and uses the VariantClear() 清理函数:

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 是一个负责内存管理的包装器。类似于_bstr_t,它管理一个BSTR;他们一起工作效果最好。与其手动设置 vt 字段和 bstrVal 值,不如使用 variant_t 构造函数或 operator=_bstr_t 将分配 BSTR 所有权并将其传递给 _variant_t。我不记得使用它的细节。只需在 MSDN 上查找详细信息。

_variant_t 超出范围时会自动清理其数据。您正在手动调用 SysFreeString(),但您没有将 bstrVal 设置为 NULL 或之后将 vt 设置为 VT_EMPTY。因此,当 variant_t 析构函数调用 VariantClear() 清理数据时,它会再次尝试释放 bstrVal 并崩溃。

所以,完全不要手动调用 SysFreeString()。如果您需要手动重置 variant_t,请改用其 Clear() 方法:

vtFld.Clear();