在我的MFC(VC2010 SP1)项目中,我广泛使用第三方库在数据库中写入一些数据。这个库很老(我发现它是为VS2005编译的),并使用_variant_t处理数据。
无论如何,在某种情况下,我会有一种奇怪的行为,我将尝试解释一下:
// .h
struct myData
{
blastuff
CString strMyCode;
};
class MyClass
{
protected:
myData m_Foo;
};
// .cpp
// In OnInitDialog:
//...
TrdPartRecordset *pRS;
//...
pRS->GetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );
现在,我开始工作,当用户按“确定”时,是时候保存到数据库并在这里开始出现问题了:
// In OnOK
TrdPartRecordset *pRS;
//...
pRS->SetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );
问题:如果我不修改m_Foo.strMyCode,那么我没有任何问题。如果我修改了该怎么办?好吧,如果m_Foo.strMyCode不包含任何数字,仍然没有问题。
相反,当我有一个数字时,会收到一个讨厌的错误:
Unhandled exception at 0x77772d37 in Mosaico.exe: 0xC0000005: Access violation reading location 0x9d7077b7.
尝试读取已删除的位置。我已经检查了手表中的m_Foo,它是正确有效的,因此我研究了库源代码:
BOOL TrdPartyRecordset::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;
}
发生的情况是vtFld在SysFreeString之前是有效的,并且在此之后销毁(我可以看到它使用调试器逐步进行了销毁),但是只有当我将数字输入strValue时才可以。如果strValue是纯字母顺序的,则不会发生这种情况。
我在Internet上进行了搜索,发现当您双重释放资源时会发生这种错误,因此我注释掉了SysFreeString并使炸弹爆炸了:不再崩溃。
不管怎么说,程序员是比我更好的程序员,所以我猜如果他把SysFreeString放进去,他就有他的理由,而且,这是我的程序中该机制崩溃的唯一部分。
我的问题是:注释掉SysFreeString会丢失内存吗?
另一个:您有更好的解决方案吗?
最佳答案
原因很简单:
内存被释放两次!
_variant_t具有析构函数。将类型设置为VT_BSTR。您还将看到pojnter并输入VT_BSTR
调用函数后,您可以再次释放内存,并且析构函数也将执行相同的操作。
该代码应如下所示:
_variant_t vtFld;
if(!strValue.IsEmpty())
vtFld = strValue;
else
vtFld.vt = VT_NULL;
return PutFieldValue(lpFieldName, vtFld);