简体   繁体   English

CArray的内存泄漏

[英]Memory leaks with CArray

In example I'm working on I have following situation, a parent – children relationship configuration up to 4 levels deep stored in database. 在示例中,我正在处理以下情况,即父级-子级关系配置,最多可存储到数据库中的4个级别。 Each item has 'id' and 'name' attribute. 每个项目都有“ id”和“ name”属性。 Because my English isn't so good a picture may be of help: 因为我的英语不太好,所以图片可能会有所帮助:
我的树

So basically, each parent can have number of children (except 4th level parent, it has no children, depth of 4 is limited). 因此,基本上每个父母都可以有多个孩子(4级父母除外,它没有孩子,深度为4是有限的)。 I need an object to store that 'tree' in memory. 我需要一个对象来将“树”存储在内存中。 I decided to go with struct and array of them. 我决定使用它们的结构和数组。

struct TEST_EXT_REASON
{
    int id;
    CString name;
    CArray<TEST_EXT_REASON*, TEST_EXT_REASON*> m_arrChildren;
    TEST_EXT_REASON::TEST_EXT_REASON()
    {
        id=0;
        name="";
    }
};

CArray<TEST_EXT_REASON*, TEST_EXT_REASON*> m_arrTestExtReason;

I'm having memory leaks issues when application closes. 应用程序关闭时出现内存泄漏问题。

This is my code snippets for populating the structure: 这是我的代码片段,用于填充结构:

    void FillTestLevels(CMyView* pObject, TEST_EXT_REASON* pParent, int level, CString query)
{
    int err = mysql_query( myData1, query.GetBuffer(0), NULL );
    if(err) {
        AfxMessageBox(mysql_error(myData1)) ;
        return;
    }
    MYSQL_RES   * result;
    MYSQL_ROW   cur;
    result = mysql_store_result( myData1 ) ;
    if (!result) return;

    int cnt = mysql_num_rows(result);
    if(cnt==0) return;

    int id;
    char* desc;
    while ((cur = mysql_fetch_row(result)))
    {
        if (cur[0]) id=atoi((char *)cur[0]);
        else        id=0;
        if (cur[1]) desc = (char *)cur[1];
        else        desc = "";

        TEST_EXT_REASON* pLevel = new TEST_EXT_REASON;
        pLevel->id = id;
        pLevel->name = desc;
        if(!pParent && level==1) pObject->m_arrTestExtReason.Add(pLevel);
        else pParent->m_arrChildren.Add(pLevel);
    }
    mysql_free_result(result);

    if(level==4) return;

    if(!pParent && level==1)    
    {
        for (int i=0; i<=pObject->m_arrTestExtReason.GetUpperBound(); i++) 
        {
            TEST_EXT_REASON* pLevel = pObject->m_arrTestExtReason.GetAt(i);
            CString q_str;
            q_str.Format("SELECT id,name FROM reason_ext_lev WHERE id_parent = %d ORDER BY name", pLevel->id);
            FillTestLevels(pObject, pLevel, level+1, q_str);
        }
    }
    else
    {
        for (int i=0; i<=pParent->m_arrChildren.GetUpperBound(); i++) 
        {
            TEST_EXT_REASON* pLevel = pParent->m_arrChildren.GetAt(i);
            CString q_str;
            q_str.Format("SELECT id,name FROM reason_ext_lev WHERE id_parent = %d ORDER BY name", pLevel->id);
            FillTestLevels(pObject, pLevel, level+1, q_str);
        }
    }
}

Only in this function is where 'new' operator is used. 仅在此功能中使用“ new”运算符。

First time I'm calling this function is from 'MyView' with params 'pParent' NULL and 'level' 1, after that it's recursion at work (populating it self to the end). 第一次调用此函数是从“ MyView”使用参数“ pParent”,NULL和“ level” 1进行的,此后它在工作中递归(将其自身填充到末尾)。

pObject->DeleteTestExtReasonArrays();
str.Format("SELECT id,name FROM reason_ext_lev WHERE id_cfg = %d AND id_parent = 0 ORDER BY name", pObject-m_nConfigId);
FillTestLevels(pObject, NULL, 1, str);

This is how I'm releasing memory (in DeleteTestExtReasonArrays()): 这就是释放内存的方式(在DeleteTestExtReasonArrays()中):

void CMyView::DeleteTestExtReasonArrays()
{
    int size = m_arrTestExtReason.GetSize();
    for (int i=size-1; i>=0; i--)
    {
        TEST_EXT_REASON* pTmp = m_arrTestExtReason.GetAt(i);
        if(pTmp->m_arrChildren.GetSize()>0)
            DeleteTestExtReasonChildren(pTmp);
        m_arrTestExtReason.RemoveAt(i,1);
        delete pTmp;
        pTmp = NULL;
    }
    m_arrTestExtReason.RemoveAll();//I don't need this realy
}

void CMyView::DeleteTestExtReasonChildren(TEST_EXT_REASON* pParent)
{
    int size = pParent->m_arrChildren.GetSize();
    for (int i=size-1; i>=0; i--)
    {
        TEST_EXT_REASON* pTmp = pParent->m_arrChildren.GetAt(i);
        if(pTmp->m_arrChildren.GetSize()>0)
            DeleteTestExtReasonChildren(pTmp);
        pParent->m_arrChildren.RemoveAt(i,1);
        delete pTmp;
        pTmp=NULL;
    }
    pParent->m_arrChildren.RemoveAll();
}

The only problem is that I'm getting memory leaks and I cant find where. 唯一的问题是我遇到内存泄漏,找不到位置。 Every item is populated and at the end released. 每个项目都已填充,最后发布。 I'm working in VS6 (yes I know it's outdated but it's special case). 我正在VS6中工作(是的,我知道它已经过时了,但这是特例)。

The parent/child stuff looks ok for me, though I would prefer to put the complete destruction stuff into TEST_EX_REASON's destructor. 尽管我希望将完整的销毁内容放入TEST_EX_REASON的析构函数中,但父母/孩子的内容对我来说看起来还不错。 In my opinion, that's safer and more clearly. 我认为,这更安全,更明确。

I see a leak when a result doesn't contain rows. 当结果不包含行时,我会看到泄漏。 In this case, you return without calling mysql_free_result(result) previously. 在这种情况下,您无需事先调用mysql_free_result(result)就可以返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM