c++ - CArray 内存泄漏

标签 c++ arrays windows memory-leaks mfc

在我正在处理的示例中,我遇到了以下情况,一个父子关系配置最多 4 层深存储在数据库中。每个项目都有“id”和“name”属性。因为我的英语不太好,一张图片可能会有帮助:
my tree

所以基本上,每个父级都可以有多个子级(除了第 4 级父级,它没有子级,4 的深度是有限的)。我需要一个对象来将那棵“树”存储在内存中。我决定使用它们的结构和数组。

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;

我在应用程序关闭时遇到内存泄漏问题。

这是我用于填充结构的代码片段:

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

只有在这个函数中才会使用'new'运算符。

我第一次使用参数“pParent”为 NULL 和“level”为 1 的“MyView”调用此函数,之后它在工作中递归(自行填充到最后)。

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

这就是我释放内存的方式(在 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();
}

唯一的问题是我遇到了内存泄漏,但我找不到泄漏的位置。每个项目都被填充并在最后发布。 我在 VS6 中工作(是的,我知道它已经过时,但它是特例)。

最佳答案

parent / child 的东西对我来说看起来不错,但我更愿意将完全破坏的东西放入 TEST_EX_REASON 的析构函数中。在我看来,这样更安全也更清晰。

当结果不包含行时,我看到了泄漏。 在这种情况下,您返回之前没有调用 mysql_free_result(result)。

关于c++ - CArray 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16853665/

相关文章:

javascript - 仅返回 true boolean 值 JSON 对象

c++ - 如何在 C++ 中为 _tcsdup 函数提供 char 数组?

windows - 文本编辑器打开大(巨大的,巨大的,大的)文本文件

python - 如何列出静态链接的 python 版本中可用的所有 openssl 密码?

c++ - std::set 和 boost::shared_ptr 唯一键识别问题

c++ - 如何使用 gdb 按名称显示 vtable

C++ 编译时状态变量

javascript - 使用node js迭代json数组对象

c++ - 如何使用 Dlib 在 opencv C++ 中的地标提取中使用 "shape_predictor_68_face_landmarks.dat"

c# - 拆分所有列表框元素并将它们全部添加到一个新的字符串数组中