【发布时间】:2010-11-17 06:57:05
【问题描述】:
有人告诉我,以下代码正在泄漏内存,但我们终生无法看到:
HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
const char* strFieldName, const bool& bNullAllowed)
{
HRESULT hr = E_FAIL;
try
{
COleVariant olevar;
olevar = aRecordset->Fields->GetItem(_bstr_t(strFieldName))->Value;
if (olevar.vt == VT_BSTR && olevar.vt != VT_EMPTY)
{
strFieldValue = olevar.bstrVal;
hr = true;
}
else if ((olevar.vt == VT_NULL || olevar.vt == VT_EMPTY) && bNullAllowed)
{
//ok, but still did not retrieve a field
hr = S_OK;
strFieldValue = "";
}
}
catch(Exception^ error)
{
hr = E_FAIL;
MLogger::Write(error);
}
return hr;
}
我们假设它与 olevar 变体有关,因为泄漏的大小与从记录集中返回的字符串的大小相匹配。
我试过olevar.detach()和olevar.clear(),都没有效果,所以如果是这个原因,我应该如何释放可能在GetItem中分配的内存。如果这不是原因,那是什么原因?
编辑
我阅读了 Ray 建议的文章以及与之相关的 cmets,然后尝试:
HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
const char* strFieldName, const bool& bNullAllowed)
{
HRESULT hr = E_FAIL;
try
{
COleVariant* olevar = new COleVariant();
_bstr_t* fieldName = new _bstr_t(strFieldName);
*olevar = aRecordset->Fields->GetItem(*fieldName)->Value;
if (olevar->vt == VT_BSTR && olevar->vt != VT_EMPTY)
{
strFieldValue = olevar->bstrVal;
hr = true;
}
else if ((olevar->vt == VT_NULL || olevar->vt == VT_EMPTY) && bNullAllowed)
{
//ok, but still did not retrieve a field
hr = S_OK;
strFieldValue = "";
}
delete olevar;
delete fieldName;
}
catch(Exception^ error)
{
hr = E_FAIL;
MLogger::Write(error);
}
return hr;
}
现在显式创建和销毁 olevariant 和 bstr 的主要区别。
这使泄漏量大致减少了一半,但这里仍有一些东西在泄漏。
解决方案?
查看 Ray 关于使用 Detach 的建议,我想到了这个:
HRESULT CDatabaseValues::GetCStringField(ADODB::_RecordsetPtr& aRecordset, CString& strFieldValue,
const char* strFieldName, const bool& bNullAllowed)
{
HRESULT hr = E_FAIL;
try
{
COleVariant olevar;
_bstr_t fieldName = strFieldName;
olevar = aRecordset->Fields->GetItem(fieldName)->Value;
if (olevar.vt == VT_BSTR && olevar.vt != VT_EMPTY)
{
BSTR fieldValue = olevar.Detach().bstrVal;
strFieldValue = fieldValue;
::SysFreeString(fieldValue);
hr = true;
}
else if ((olevar.vt == VT_NULL || olevar.vt == VT_EMPTY) && bNullAllowed)
{
//ok, but still did not retrieve a field
hr = S_OK;
strFieldValue = "";
}
::SysFreeString(fieldName);
}
catch(Exception^ error)
{
hr = E_FAIL;
MLogger::Write(error);
}
return hr;
}
根据工具(GlowCode),这不再泄漏,但我担心在将 SysFreeString 分配给 CString 之后在 fieldValue 上使用它。它似乎可以运行,但我知道这并不意味着没有内存损坏!
【问题讨论】:
-
您的帖子让我想到了 BSTR 值。我没有确切地遇到这个问题,但我有以下导致内存泄漏的代码。花了很多时间将其缩小到这行代码。抱歉格式化问题。
void GetValue(COleVariant& oVar) { . . . //oVar.Clear(); -- memory leak because of following line without this call if bstr was allocated for this variant!! oVar.Vt = VT_I4; oVar.lVal = 100; }
标签: c++ mfc memory-leaks