【发布时间】:2017-01-02 11:39:48
【问题描述】:
我的泄漏检查器告诉我这个函数有第二次机会异常。
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 需要使用 SystemFreeString() 取消分配 BSTR,这是在上面的代码中完成的,但是由于这个 BSTR 是 _variant_t 的成员,他有自己的析构函数可以清理,谁应该真正清理bstrVal 成员在这种情况下?
inline _variant_t::~_variant_t() throw()
{
::VariantClear(this);
}
在我看来,这似乎试图再次清理已被SysFreeString() 清理的内存导致异常? documentation 说它清除了变体,但不清楚它到底清除了什么,它是否也释放了 bstrVal?
如果我删除调用 SysFreeString(vtFld.bstrVal); 这确实删除了第二次机会异常,但我真的很想知道这是正确的做法,因为文档没有提供足够的信心。
【问题讨论】:
-
你的帮助太大了,像
_variant_t这样的包装类从来都不是一个好主意。 BSTR 被删除两次,一次被您删除,一次被 variant_t 删除。您也不应该访问其字段。您只需要_variant_t vtFld(strValue);或vtFld = strValue;,其余的都是自动的。 -
@HansPassant:由于
VT_NULL需要在strValue为空时传递给PutFieldValue(),因此使用类似这样的东西会更正确:_variant_t vtFld; if(!strValue.IsEmpty()) vtFld = strValue; else vtFld.vt = VT_NULL; return PutFieldValue(lpFieldName, vtFld);