Мне сказали пару инструментов, что в следующем коде происходит утечка памяти, но мы не можем за всю жизнь увидеть, где:
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. И если это не причина, то что?
EDIT
Я прочитал статью, предложенную Рэем, а также комментарии, связанные с ней, а затем попытался:
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 теперь явно создаются и уничтожаются.
Это примерно вдвое сократило объем утечки, но здесь есть что-то, что протекает.
Решение
Глядя на совет Рэя по использованию 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 для fieldValue после того, как он был назначен CString. Кажется, он работает, но я знаю, что это не свидетельствует о том, что память не повреждена!