2009-08-06 8 views
4

私は次のコードは、メモリをリークしているツールのカップルも言われているが、どこ私たちは私たちの生活のために見ることができない:私たちは、OLEVARバリアントとは何かであると仮定この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.detach()とolevar.clear()はどちらも効果がありませんでした。これが原因であれば、おそらくGetItemに割り当てられているメモリを解放します。そして、これが原因でないなら、何がありますか?

EDIT

私はレイによって提案された記事を読み、またそれに関連するコメントや、その後試してみました:olevariantとBSTRいる

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; 
} 

主な違いは、現在、明示的に作成および破棄されます。

これはリークの量を約半分にしましたが、ここに漏れているものがまだあります。

解決策?デタッチの使用についてのレイからアドバイスを見てみると

は、私はこの思い付いたん:

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値について考えさせてくれました。私は厳密にこの問題を抱えていませんでしたが、私はメモリリークを引き起こしたコードを次のように持っています。このコード行に絞るにはかなりの時間がかかりました。書式設定の問題で申し訳ありません。 'GetValue(COleVariant&oVar)void { 。 。 。 //oVar.Clear(); - この変種のためにbstrが割り当てられていた場合、この呼び出しがないと次の行のためメモリリークが発生する!! oVar.Vt = VT_I4; oVar.lVal = 100; } ' – Patel

答えて

6

BSTRに割り当てられたメモリを解放する必要があります。

article

ああを参照してください、あなたはCStringの

strFieldValue = olevar.detach().bstrVal; 

をVARIANTのBSTR値を割り当てる前に切り離しを行い、その後、あなたのCStringオブジェクトが正しく時間内に破壊されますことを確認する必要があります。

+0

あなたはCOleVariantのデストラクタがそれを行うとは思いますが...実際に今何が行われているのかは実際は確認できません。 – Goz

+0

実際には、MFCソースを調べます。 〜COleVariantは "VariantClear"を呼び出し、VariantClearのドキュメントに従います

"vtフィールドがVT_BSTRの場合、文字列は解放されます" – Goz

+0

このCosherはManaged C++になっていますか?オレンバーがスコープの外に出て参照(strFieldValue)になったときに破壊されるsomehtingを割り当てています。アンマネージC++ではstrFieldValueが偶然によってのみ正しいことを意味します。 –

2

このコードスニペットでは、例外ハンドラのメモリがリークする可能性があります。言い換えると、この関数は例外的に安全ではありません。

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

あなたは、あなたがdeleteラインに到達する前にnewを呼び出した後、例外がスローされた場合にolevarまたはfieldNameをクリーンアップすることはありません。

スマートポインタ(std::auto_ptrboost::scoped_ptr)を使用して、ポインタの使用を終了すると自動的にポインタを解放することをお勧めします。

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

良い点、ありがとう。私もこれを調べます。 –

関連する問題