2009-08-06 57 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