2009-08-06 107 views
4

有人告訴我是一對夫婦,下面的代碼被泄漏內存工具,但我們不能讓我們的生命看到:哪裏是在該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; 
} 

我們假設它是值得做的olevar變種因爲泄漏的大小與從記錄集返回的字符串的大小相匹配。我試過olevar.detach()和olevar.clear(),都沒有效果,所以如果這是原因,我該如何釋放大概在GetItem中分配的內存。如果這不是原因,那是什麼?

編輯

我讀到雷建議的文章,也與此相關的意見,然後嘗試:

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現在明確創建和銷燬。

這已經大致減半泄漏量,但仍有一些在這裏正在泄漏。

解決方案?

看着雷有關使用拆離的建議,我想出了這個:

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)這不再漏水,但我很擔心使用上fieldValue方法SysFreeString在它被分配給CString之後。它似乎在運行,但我知道這並不是沒有任何內存腐敗的跡象!

+0

您的文章使我想到BSTR值。我沒有這個問題確切,但我有一段代碼導致內存泄漏。花了相當多的時間縮小到這行代碼。抱歉格式問題。 'void GetValue(COleVariant&oVar) { 。 。 。 //oVar.Clear(); - 如果bstr被分配給這個變體,沒有這個調用的話會因爲下一行而導致內存泄漏! oVar.Vt = VT_I4; oVar.lVal = 100; }' – Patel 2017-12-12 01:54:43

回答

6

你必須釋放分配給BSTR內存。

article

哦,你以前VARIANT的BSTR分配值做一個分離,以CString的

strFieldValue = olevar.detach().bstrVal; 

,然後確保您的CString對象被及時妥善銷燬。

+0

雖然COleVariant的析構函數會爲你做這件事,但是......現在無法真正檢查它的功能。 – Goz 2009-08-06 09:17:46

+0

其實,通過MFC來源看。 〜COleVariant調用「VariantClear」並根據文檔VariantClear

「如果vtfield是VT_BSTR,字符串被釋放」 – Goz 2009-08-06 09:22:23

+0

無論如何,這是猶太教在託管C + +嗎?你正在分配一些將在olevar超出範圍時被銷燬的引用(strFieldValue),在非託管C++中這通常意味着strFieldValue只能通過巧合來糾正。 – 2009-08-06 09:49:19

2

這段代碼可以在異常處理程序泄漏內存。換句話說,這個函數並不是特例安全的。

catch(Exception^ error) 
{ 
    hr = E_FAIL; 
    MLogger::Write(error); 
} 

你永遠不清理olevarfieldName在事件拋出一個異常,你之前調用new後到達delete線。

我建議您使用某種智能指針(std::auto_ptr,boost::scoped_ptr)在您完成使用時自動釋放指針。

std::auto_ptr<COleVariant> olevar(new COleVariant); 
+0

好點,謝謝。我也會研究這一點。 – 2009-08-06 11:29:22