删除为列表分配的内存

时间:2012-12-11 11:31:02

标签: c++ list memory delete-operator

查看以下代码。在执行开始时的代码中,内存使用量为1020K。但在执行结束时,内存使用量为1144K。有人可以帮我识别内存泄漏。如果调用func()五次,则内存使用量将达到1500K +。如果我们不使用该列表,则内存使用量不会增加。

void func();

int _tmain(int argc, _TCHAR* argv[])
{
    func();
    return 0;
}

void func()
{
    list<char*> list1;
    list<char*>::iterator iter;
    char* val;
    for(int i=0; i<100000; i++)
    {
        val = new char[20];
        for(int j=0; j<20;j++)
        {
            val[j] = 'A';
        }
        val[19] = '\0';
        list1.push_back(val);
    }

    iter = list1.begin();
    for(int k=0; k<100000;k++, iter++)
    {
        delete[] *iter;
        *iter = NULL;
    }
    val = NULL;

    list1.clear();
    list1.empty();
}

1 个答案:

答案 0 :(得分:3)

我看到没有内存泄漏,但我确实看到很多非常糟糕的代码。

我在你的代码中看到了一些你在Windows下运行的提示,当我凝视我的水晶球时,我想我会看到你检查任务管理器以检测内存泄漏。使用任务管理器检测内存泄漏就像使用大刀进行手术一样。 TM可能会给你一个暗示可能是系统中存在大量内存泄漏的提示,但是它与程序相距太远而且太粗糙而无法确定。您需要使用专用于该作业的工具,而不是使用TM来确定是否存在内存泄漏。内置Visual Studio has such a tool

当我在你的代码中使用这些内置功能时:

#include <cstdlib>
#include <list>
using std::list;

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>


void func();

int main(int argc, char* argv[])
{
    func();
    return 0;
}

void func()
{
    list<char*> list1;
    list<char*>::iterator iter;
    char* val;
    for(int i=0; i<100000; i++)
    {
        val = new char[20];
        for(int j=0; j<20;j++)
        {
            val[j] = 'A';
        }
        val[19] = '\0';
        list1.push_back(val);
    }

    iter = list1.begin();
    for(int k=0; k<100000;k++, iter++)
    {
        delete[] *iter;
        *iter = NULL;
    }
    val = NULL;

    list1.clear();
    list1.empty();

    _CrtDumpMemoryLeaks();
}

......我明白了:

Detected memory leaks!
Dumping objects ->
{142} normal block at 0x00000000000778C0, 24 bytes long.
 Data: < x       x      > C0 78 07 00 00 00 00 00 C0 78 07 00 00 00 00 00 
{141} normal block at 0x0000000000077840, 16 bytes long.
 Data: <(       h       > 28 F7 1A 00 00 00 00 00 68 F7 1A 00 00 00 00 00 
Object dump complete.

报告了总共40个字节的两个内存泄漏,因此这里没有广泛的内存泄漏。此外,这些可能是误报,报告CRT的静态内存分配等事情,应予以忽略。

然而,正如我所说,我确实看到很多非常糟糕的代码。这不是导致内存泄漏的原因,但它们很容易出现在实际代码中。

  1. 您使用了大量magic numbers 。例如使用for(int i=0; i<100000; i++),您应该迭代列表(for( list<char*>::iterator it = list1.begin(); it != list1.end(); ++it)),或者至少询问列表它有多少元素(for( size_t i = 0; i < list1.size(); ++i )

  2. 您正在使用动态分配/解除分配。您应该在确实需要动态分配的情况下使用RAII,但应尽可能避免动态分配。在您的情况下,您应该使用list<char*>而不是list<std::string>

  3. 您正在使用标准库提供的算法的地方使用手写循环。你从不写的代码是最可靠的代码。只需执行std::string s(20,'A')而不是内部循环初始化char数组,而不是设置每个列表成员的外部循环,而是使用类似copytransform的内容。

  4. 编辑以下是您的函数的重新版本,它解决了我在上面提到的一些问题:

    #include <string>
    using std::string;
    #include <algorithm>
    using std::generate_n;
    #include <iterator>
    using std::back_inserter;
    
    void func()
    {
        static const size_t NumStrings = 10000;
        typedef list<string> strings;
    
        // Populate the list
        strings list2;
        generate_n(back_inserter(list2), NumStrings, []() -> string
        {
            static const size_t NumChars = 19;
            static const char InitChar = 'A';
            return string(NumChars, InitChar);
        });
    
        // Clear the list
        list2.clear();
    
        // Done
        _CrtDumpMemoryLeaks();
    }
    

    generate_n的调用使用了C ++ 11 lambda,但很容易被重构为完全使用仿函数或其他东西。