首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这个C++中的内存泄漏在哪里?

这个C++中的内存泄漏在哪里?
EN

Stack Overflow用户
提问于 2009-08-06 09:06:59
回答 2查看 2.5K关注 0票数 4

有几个工具告诉我,下面的代码正在泄漏内存,但我们无法在我们的生活中看到它的位置:

代码语言:javascript
复制
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中分配的内存。如果这不是原因,那是什么原因?

编辑

我阅读了Ray提出的文章以及与之相关的评论,然后尝试:

代码语言:javascript
复制
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现在被显式地创建和销毁了。

这大约减少了一半的泄漏量,但仍有一些东西在泄漏。

溶液?

看看Ray关于使用Detach的建议,我想出了如下建议:

代码语言:javascript
复制
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被分配给CString之后,在fieldValue上使用它。它似乎在运行,但我知道这并不意味着没有内存损坏!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-08-06 09:12:15

您必须释放分配给BSTR的内存。

请参阅文章

哦,在将变量的bstr值赋值给CString之前,您必须先做一个分离。

代码语言:javascript
复制
strFieldValue = olevar.detach().bstrVal;

然后确保及时正确销毁CString对象。

票数 6
EN

Stack Overflow用户

发布于 2009-08-06 11:18:34

此代码段可能会泄漏异常处理程序中的内存。换句话说,这个函数不例外安全。

代码语言:javascript
复制
catch(Exception^ error)
{
    hr = E_FAIL;
    MLogger::Write(error);
}

在调用olevar后和到达delete行之前抛出异常时,您永远不会清理newdelete

我建议您使用某种智能指针(std::auto_ptrboost::scoped_ptr),以便在使用完这些指针后自动释放它们。

代码语言:javascript
复制
std::auto_ptr<COleVariant> olevar(new COleVariant);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1237768

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档