【问题标题】:Memory leak with template for pointers and ints. What am i doing wrong?指针和整数模板的内存泄漏。我究竟做错了什么?
【发布时间】:2016-08-10 03:06:13
【问题描述】:

开始了解 C++,并尝试将类模板化以使用结构的 Ints 和 Pointers。 输出符合预期,但使用 valgrind 进行测试时,似乎有一个内存韭菜,来自未释放的内存。

我相信这与我在类 init 中声明列表变量的方式有关。

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

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

【问题讨论】:

  • 为什么不直接使用vector
  • 为什么main 中的newdelete 业务无用?顺便说一句,#include &lt;stdio.h&gt; 应该是 #include &lt;cstdio&gt;,前者是合法的,但自第一个标准以来已被弃用。另外,请查看&lt;iostream&gt;,它是标准 C++ I/O。
  • @jaggedSpire 无论如何都不会伤害到链接到文档,他越早避开这个自制的东西越好。老实说,我对麻省理工学院这样的机构的期望更高,但另一方面,它是一个“学习 C/C++ 的网站”。 ://
  • @ROX 希望如此,尽管 typedefed struct 并没有给我太多希望,他们在类中与 C 大相径庭。
  • 等等,OP,你在什么系统上运行?如果是 Mac OS X,请尝试注释掉 printf 语句并再次运行。 valgrind occasionally finds potential leaks 与标准输出 on that OS.

标签: c++ templates memory-leaks valgrind


【解决方案1】:

首先非常仔细和完整地阅读 valgrind 输出(并按照 valgrind 的建议做所有事情)。在您的情况下,感兴趣的片段是:

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

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

您还应该注意以下事项: http://valgrind.org/docs/manual/faq.html#faq.reports(4.1。我的程序使用 C++ STL 和字符串类。Valgrind 在程序退出时报告涉及这些类的“still reachable”内存泄漏,但应该没有)。

如果您有时间,您可能会从详细了解中受益匪浅:http://valgrind.org/docs/manual/mc-manual.html#mc-manual.leaks(4.2.8. 内存泄漏检测)。

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

【讨论】:

    【解决方案2】:

    对基本数据结构有很强的掌握是很好的!我鼓励你充分探索它。一旦掌握了基础知识,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)
    }
    

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

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

    在 Valgrind 下运行这个程序会显示 Invalid write 错误。试试看吧。

    【讨论】:

    • 我使用建议的标志运行了 valgrind 测试,但确实遇到了写入错误。
    • 对。 C++ 中的内存管理很棘手。如果我的回答有帮助,将不胜感激。谢谢
    • @or.ohev-zion 如果我的回答有帮助,我们将不胜感激。
    猜你喜欢
    • 2013-08-06
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    相关资源
    最近更新 更多