在我的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);

09-27 11:28