【问题标题】:C++ Memory Leak, Can't find whereC++ 内存泄漏,找不到在哪里
【发布时间】:2011-02-05 19:29:39
【问题描述】:

我正在使用 Visual Studio 2008,开发 OpenGL 窗口。我创建了几个用于创建骨架的类,一个用于关节,一个用于皮肤,一个用于 Body(它是多个关节和皮肤的支架),还有一个用于读取 skel/skin 文件。

在我的每个类中,我对大部分数据都使用了指针,其中大部分是使用 = new int[XX] 声明的。我为每个删除指针的类都有一个析构函数,使用 delete[XX]。

在我的 GLUT 显示函数中,我让它声明一个主体,打开文件并绘制它们,然后在显示结束时删除主体。但是程序中的某个地方仍然存在内存泄漏。随着时间的推移,它的内存使用量只会以一致的速度不断增加,我将其解释为不会被删除的东西。

我不确定是不是在 glut 显示函数中没有删除 Body 类,还是其他什么。我已经按照 Visual Studio 2008 中的内存泄漏检测步骤进行操作,它没有报告任何泄漏,但我不能 100% 确定它是否适合我。我的 C++ 不流利,所以可能有些东西我忽略了,有人能看到吗?

从主要:

void display(void){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    Body *body = new Body();
    body->readSkel("C:\\skel2.skel");
    body->drawBody();
    body = new Body();
    body->readSkel("C:\\skel1.skel");
    body->drawBody();
    glutSwapBuffers();  
    body->~Body();
    delete body;
}

来自正文:

Body::Body(){
    skelFile = string();
    skinFile = string();
    totalJoints = 0;
    joints = new Joint[25];
    skin = new Skin;
}

Body::~Body(){
    delete[25] joints;
    delete skin; 
}

【问题讨论】:

  • 请停止编码并阅读 Scott Meyers 的 Effective C++ 第 3 版。我并不是要刻薄,但我很想创建一个长答案,以解决您的一些编码错误和不良做法。 Scott Meyers 的书将帮助您更好地编写代码。特别是第 4 项和第 14 项。
  • 会的。抱歉,我已经很久没有学 C++了,我们学校现在只教 Java(糟透了,对吧?)而且老师强迫我们使用 C/C++,而没有先给我们展示任何东西。我

标签: c++ opengl memory-management memory-leaks freeglut


【解决方案1】:

在这段代码中:

Body *body = new Body();
body->readSkel("C:\\skel2.skel");
body->drawBody();
body = new Body();

你泄露了Body,因为你没有删除第一个。

还有这个:

body->~Body();
delete body;

很奇怪。您不会像那样显式调用析构函数 - delete 负责调用析构函数。

这段代码:

delete[25] joints;

也很奇怪。正确的形式是:

delete [] joints;

您使用的是非标准语法,25 将被忽略。请参阅this question 了解更多信息。

【讨论】:

  • 我的错,我在我的代码中交换了它们,实际上有一个被注释掉了......这很有效,我知道我在那里做了什么......非常感谢。
  • 对 body 的额外析构函数调用可能会导致关节和皮肤的双重删除 - 我很惊讶这没有崩溃。
  • @RichieHindle - body->~Body(); delete body 不仅奇怪,而且在他的示例中可能导致未定义的行为。析构函数将被调用两次,由于他的代码没有将jointsskin 设置为0,因此代码将双重删除,这可能会导致UB。
  • 正如我所说,在我的实际代码中,两者实际上都不存在,只是其中一个,我只是在进行一些调试。
【解决方案2】:

真正的程序员可以用任何语言编写FortranJava! Java 要求您(实际上)动态分配所有内容,但 C++ 不需要。

由于没有其他人指出(至少直接指出),在display 中似乎根本没有理由使用动态分配。只需执行以下操作:

void display(void){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    Body body;
    body.readSkel("C:\\skel2.skel");
    body.drawBody();

    Body body2;
    body2.readSkel("C:\\skel1.skel");
    body2.drawBody();
    glutSwapBuffers();  
}

如果您的readSkel 清除了现有的骨架数据,则无需定义body2,但在不知情的情况下,这是保证安全的简单方法。

同样,在您对 Body 的定义中,您似乎也没有做任何需要动态分配的事情。

class Body { 
    std::string skelFile;
    std::string skinFile;
    int totalJoints;
    Skin skin;
    Joint joints[25];
public:
    Body() : totalJoints(0) {}
};

或者更好:

class Body { 
    std::string skelFile;
    std::string skinFile;
    Skin skin;
    std::vector<Joint> joints;
public:
   // presumably other stuff goes here...but you don't need a ctor or dtor.
};

这消除了泄漏任何东西的大多数机会(至少在代码的这些部分中——因为我们没有看到你的 Skin 或 Joint 类,所以很难猜测它们可能在做什么......

【讨论】:

  • 是的,很好的建议。除非必须,否则不要使用动态分配。
【解决方案3】:

如果您粘贴一些代码会有所帮助,但我会:

仔细检查您的语法: int *foo = new int[size];删除[] foo;

确保所有父级使用动态内存的子类也包含析构函数,即使析构函数是空语句。

【讨论】:

  • 代码如下。我已经确保对于每一个新的,我都有一个删除。
  • 也许我今天早上没有喝足够的咖啡,但是我看到两个新的 Body() 语句分配内存,但只有一个调用了析构函数。你的第一个身体会发生什么?
【解决方案4】:

Jochen Kalmbach 是你的朋友。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    相关资源
    最近更新 更多