2

我无法理解 C++ 中的一些基本内存管理原则。此代码是循环的一部分,循环是将迷宫文件读入二维向量的函数的一部分。

根据 Valgrind 的说法,以下代码导致内存泄漏......

请注意,它t是一个MazeNode对象,并且vertst类中的一个向量,其中包含指向节点对象的指针(不要与MazeNode对象混淆):

node* top = new node(TOP, rowCount, i, t.type);
node* bot = new node(BOTTOM, rowCount, i, t.type);
node* left = new node(LEFT, rowCount, i,  t.type);
node* right = new node(RIGHT, rowCount, i, t.type);

t.verts.push_back(top);
t.verts.push_back(bot);
t.verts.push_back(left);
t.verts.push_back(right);

temp.push_back(t);

top = NULL;
bot = NULL;
left = NULL;
right = NULL;
delete top;
delete bot;
delete left;
delete right;

最初我在删除它们之前没有将每个指针设置为 NULL,但会出现分配错误。所以我只是将它们设置为 NULL 并且我的代码有效。我想我真的很困惑为什么这会导致内存泄漏以及为什么我需要将指针设置为 NULL。可能有一种更简单的非指针方法可以做到这一点,但也许这个问题会帮助我更好地理解内存管理。

谢谢大家。

编辑:这是 MazeNode 类(这就是“t”)(也请原谅我写这个类的懒惰,让一切都像结构一样公开)

class MazeNode 
{
public:
    void setType(char c);
    char getChar();

    NodeType type;
    vector<Direction> visitedFrom;

    vector<node*> verts;
};

和节点类:

class node
{
public:
    node();
    node(Direction d, int r, int c, NodeType t);
    ~node(); //empty definition
    node(const node* n);
    node& operator=(const node& n);

    void addAdj(node* a, int w);
    void printAdj() const;
    string direction() const;

    void print() const;
    bool operator<(const node& n) const;


    int distance; //from start
    bool visited;
    node* prev;
    vector<Edge> adj;
    Direction dir;
    int row, col;
    NodeType type;
};

EDIT2:谢谢大家。我现在明白了这个问题。我更改了指针对象的向量,以便不再使用指针。

4

6 回答 6

9

在添加空分配之前,您的代码有一个与内存泄漏不同(更糟)的问题:存储并且可能还使用了一个杂散指针,即指向已释放内存的指针。

通过添加空分配使其成为内存泄漏会使其变得更好,但不会太多。

真正的解决方案是在调用 delete 之后不要在任何地方保留任何指针。也就是说,不要push_back或不要delete在这里。

于 2012-04-16T22:00:49.143 回答
4

您将指针放入容器中,然后删除指针。当您的代码稍后尝试使用这些指针时,它们无效并导致崩溃。

通过在删除它们之前将指针设置为 NULL,您最终根本不会删除它们 - 删除 NULL 指针不会做任何事情。但是现在以后没有什么可以删除对象了,而且你会遇到内存泄漏。

您需要在代码中找到不再使用指针的位置,然后将其删除。

编辑:当然我应该提到一个智能指针,比如std::shared_ptr完全消除了这个麻烦,因为它会自动删除对象。

于 2012-04-16T22:04:10.050 回答
2

您在删除它们之前将值设置为 NULL,因此您尝试删除 NULL 并且没有任何内容被删除。尝试将删除调用移到 NULL 调用之上。

于 2012-04-16T21:57:45.740 回答
2

这种困惑正是我为这些事情创建宏的原因:

#define delobj(obj) (delete obj, obj = NULL)

你会像这样使用它:

delobj(top);
delobj(bot);
delobj(left);
delobj(right);
于 2012-04-16T21:59:59.173 回答
2

错误是使用指针向量。据你说, verts 是这样的:

vector<node*> verts;

但它应该是这样的:

vector<node> verts;

在第一种情况下,当您 push_back() 指针时,没关系,但是当您 pop_back 或以其他方式重新调整向量的大小时,指针是向量的“内容”,并且被取消分配,但不是指针指向,也就是节点。因此节点泄漏。但在第二种情况下,节点是向量的“一部分”,并且在重新调整向量大小的过程中被分配/解除分配。

您在此处的模式可能表示 Java/C# 背景,因为在这些语言中“新建”到容器中非常常见,但要在 C++ 中做到这一点,您需要一个智能指针容器(比如vector<shared_ptr<node>>或其他东西),即可能超出了问题的范围。但是在那些语言中,对引用类型的每个引用都是一个“智能指针”(或多或少),因此这是自动完成的。C++ 不是这样的。

您要么需要更改代码以使用 a vector<node>(并更改您推回它的方式),要么需要在向量缩小时显式取消分配节点。

于 2012-04-16T22:06:20.593 回答
0

改成:

delete top;
delete bot;
delete left;
delete right;

top = NULL;
bot = NULL;
left = NULL;
right = NULL;

它应该工作。

于 2012-04-16T21:59:19.977 回答