在我的 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 );
现在,我完成我的工作,当用户按下 OK 时,是时候保存到数据库了,问题就在这里开始:
// In OnOK
TrdPartRecordset *pRS;
//...
pRS->SetFieldValue( _T("MyDBColumn"), m_Foo.strMyCode );
问题:如果我不修改m_Foo.strMyCode,我没有任何问题。如果我修改它呢?好吧,如果 m_Foo.strMyCode 确实NOT 包含任何 数字,仍然没有问题。 相反,当我有一个数字时,我得到一个讨厌的错误:
Unhandled exception at 0x77772d37 in Mosaico.exe: 0xC0000005: Access violation reading location 0x9d7077b7.
这是试图读取已删除的位置。我检查了 watch 中的 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。您还会看到指针并键入 VT_BSTR
在您调用的函数之后,您再次释放内存,析构函数执行相同的操作。
代码应该是这样的:
_variant_t vtFld;
if(!strValue.IsEmpty())
vtFld = strValue;
else
vtFld.vt = VT_NULL;
return PutFieldValue(lpFieldName, vtFld);
关于c++ - 关于 MFC 库中的 _variant_t 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22791678/