On m'a dit être quelques outils que le code suivant est une fuite de mémoire, mais nous ne pouvons pas pour la vie de nous voir où:Où est la fuite de mémoire dans ce C++?
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;
}
Nous partons du principe qu'il est quelque chose à voir avec la variante olevar car la taille de la fuite correspond à la taille de la chaîne renvoyée par le jeu d'enregistrements.
J'ai essayé olevar.detach() et olevar.clear(), les deux n'ont eu aucun effet, donc si c'est la cause, comment je libère la mémoire qui est vraisemblablement allouée dans GetItem. Et si ce n'est pas la cause, qu'est-ce que c'est?
EDIT
Je lis l'article proposé par Ray et aussi les commentaires qui y sont associés, puis essayé:
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;
}
différences principales étant le OleVariant et bstr sont désormais explicitement créés et détruits.
Cela a réduit de moitié le volume de fuite, mais il y a encore quelque chose qui fuit ici.
Solution?
regardant les conseils de Ray sur l'utilisation Détacher, je suis venu avec ceci:
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;
}
Selon l'outil (GlowCode) ce n'est plus une fuite, mais je suis inquiet sur l'utilisation SysFreeString sur fieldValue après avoir été affecté au CString. Il semble fonctionner, mais je sais que ce n'est pas une indication d'être sans corruption de la mémoire!
votre publication m'a fait penser aux valeurs BSTR. Je n'ai pas eu ce problème, mais j'ai un morceau de code qui a entraîné une fuite de mémoire. Il a fallu un peu de temps pour le réduire à cette ligne de code. Désolé pour le problème de formatage. 'void GetValue (COleVariant & oVar) { . . . //oVar.Clear(); - fuite de mémoire à cause de la ligne suivante sans cet appel si bstr a été alloué pour cette variante !! oVar.Vt = VT_I4; oVar.lVal = 100; } ' – Patel