内存泄漏与指针和整数模板。我究竟做错了什么?

时间:2016-08-09 15:51:13

标签: c++ templates memory-leaks valgrind

了解C ++,并尝试模拟一个类与Ints和Pointers一起使用结构。 输出是预期的,但是使用valgrind进行测试似乎有一个内存韭菜,来自不同意的内存。

我认为这与我在init类中声明list变量的方式有关。

我缺少什么,我该如何解决? 感谢。

#include <stdio.h>

template <class T>
class List {
    T* list;

public:
    int length;

    List(int len) {
        list = new T[len];
        length = len;
    }

    virtual ~List() {
        delete[] list;
    }

    T get(int index) {
        return list[index];
    }

    void set(int index, T val) {
        list[index] = val;
    }
};
/*
    You shouldn't change the code below, unless you want to _temporarily_ change the main function while testing.
    Change it back when you're done.
*/
typedef struct Point_ {
    int x;
    int y;
} Point;

int main(){
    List<int> integers(10);
    for(int i = 0; i < integers.length; i++){
        integers.set(i, i * 100);
        printf("%d ", integers.get(i));
    }
    printf("\n"); // this loop should print: 0 100 200 300 400 500 600 700 800 900

    List<Point *> points(5);
    for(int i = 0; i < points.length; i++) {
        Point *p = new Point;
        p->x = i * 10;
        p->y = i * 100;
        points.set(i, p);
        printf("(%d, %d) ", points.get(i)->x, points.get(i)->y);
        delete p;
    }
    printf("\n"); // this loop should print: (0, 0) (10, 100) (20, 200) (30, 300) (40, 400)
}

用这样的g ++编译:

g++ -Wall p2_templates.cpp -o p2_templates

使用valgrind使用此命令:

valgrind --tool=memcheck ./p2_templates

从valgrind获得此结果:

==22396== Memcheck, a memory error detector
==22396== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==22396== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==22396== Command: ./p2_templates
==22396== 
0 100 200 300 400 500 600 700 800 900 
(0, 0) (10, 100) (20, 200) (30, 300) (40, 400) 
==22396== 
==22396== HEAP SUMMARY:
==22396==     in use at exit: 72,704 bytes in 1 blocks
==22396==   total heap usage: 9 allocs, 8 frees, 73,848 bytes allocated
==22396== 
==22396== LEAK SUMMARY:
==22396==    definitely lost: 0 bytes in 0 blocks
==22396==    indirectly lost: 0 bytes in 0 blocks
==22396==      possibly lost: 0 bytes in 0 blocks
==22396==    still reachable: 72,704 bytes in 1 blocks
==22396==         suppressed: 0 bytes in 0 blocks
==22396== Rerun with --leak-check=full to see details of leaked memory
==22396== 
==22396== For counts of detected and suppressed errors, rerun with: -v
==22396== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

2 个答案:

答案 0 :(得分:4)

首先阅读valgrind输出,非常小心和完整(并做了valgrind推荐的一切)。在您的情况下,感兴趣的片段是:

  

重新运行 - leak-check = full 以查看泄漏内存的详细信息

     

仍然可以访问:1个块中72,704个字节

您还应该了解以下内容: http://valgrind.org/docs/manual/faq.html#faq.reports(4.1。我的程序使用C ++ STL和字符串类.Valgrind在程序出口处报告'仍然可达'内存泄漏涉及这些类,但应该没有)。

如果你有时间,你可能会对此有详细的了解:http://valgrind.org/docs/manual/mc-manual.html#mc-manual.leaks(4.2.8。内存泄漏检测)。

最后,你可以在这里找到大量有用的信息:http://valgrind.org(valgrind主页)。

答案 1 :(得分:1)

掌握基本数据结构很好!我鼓励你充分探索它。一旦掌握了基础知识,那么STL对于处理繁忙的工作非常有用,同时您可以考虑难题。

您的代码中没有泄漏。 Valgrind正在其他地方看到记忆,如前所述,你可以使用--leak-check = full来获取更多细节。你想要了解这些细节是好的。

然而,这是一个悬空指针问题。

#include <stdio.h>

template <class T>
class List {
    T* list;

public:
    int length;

    List(int len) {
        list = new T[len];
        length = len;
    }

    virtual ~List() {
        delete[] list;
    }

    T get(int index) {
        return list[index];
    }

    void set(int index, T val) {
        list[index] = val;
    }
};
/*
    You shouldn't change the code below, unless you want to _temporarily_ change the main function while testing.
    Change it back when you're done.
*/
typedef struct Point_ {
    int x;
    int y;
} Point;

int main(){
    List<int> integers(10);
    for(int i = 0; i < integers.length; i++){
        integers.set(i, i * 100);
        printf("%d ", integers.get(i));
    }
    printf("\n"); // this loop should print: 0 100 200 300 400 500 600 700 800 900

    List<Point *> points(5);
    for(int i = 0; i < points.length; i++) {
        Point *p = new Point;
        p->x = i * 10;
        p->y = i * 100;
        points.set(i, p);
        printf("(%d, %d) ", points.get(i)->x, points.get(i)->y);
        delete p;
    }
    Point* fail = points.get(0);
    fail->x = 0;
    fail->y = 0;
    printf("\n"); // this loop should print: (0, 0) (10, 100) (20, 200) (30, 300) (40, 400)
}

请注意,我在点循环后添加了'fail'变量来演示问题。声明并填充points变量,然后删除内容。列表保存Point *而不是Point,因此当删除发生时,List中的指针是“悬空”。悬空指针使用几乎每次都会崩溃或损坏堆。当持有指针时,这也是STL容器的常见问题。

C ++的一个重大缺陷是堆管理。正确使用堆是非常困难的,最大的问题是所有权交还。悬挂指针或泄漏通常是由谁拥有指针的混淆造成的。这里有一篇简短的文章Avoiding Leaks in C++

在Valgrind下运行此程序将显示无效写入错误。试一试。