适当破坏某些班级成员

时间:2014-02-05 08:03:40

标签: c++ memory-leaks garbage-collection

我有一个带有几个指针成员的类,可以重新分配。当我使用LoadOBJ()函数时,我应该替换已经保存的数据,但我在垃圾收集方面遇到了麻烦。下面是一些代码。

class Object3d{

public:

int nVertex;
int nFace;
int nVertexNormal;

Vector3d *vertex;
Vector3d *vertexNormal;
Face3d *face;

void LoadOBJ(char*);
Object3d():nVertex(0), nFace(0), vertex(NULL), face(NULL){}
Object3d(char*);
~Object3d(){}
};

Face3d:

struct Face3d{
int nFaceV;
int *iVertex;
int *iVertexNormal;

Face3d():nFaceV(0){}
};

每次我使用LoadOBJ()函数加载一个新对象时,我想删除以前分配的内存,而不是仅使用new并泄漏先前分配的内存。

我不知道该怎么做。这就是我现在想到的:

void *vGarbage, *vGarbage2, 
     *fGarbage,
     *iGarbage, *iGarbage2;

//nFace is the previous number of faces; in the case of a new object, it's 0
            for(int i=0; i<nFace; i++) 
            {
                    iGarbage=face[i].iVertex;
                    iGarbage2=face[i].iVertexNormal;
                    delete[] iGarbage;
                    delete[] iGarbage2;
            }

            vGarbage=vertex; 
            fGarbage=face; 
            vGarbage2=vertexNormal;

            delete[] vGarbage;
            delete[] vGarbage2;
            delete[] fGarbage;

以上代码每次使用LoadOBJ()时都会运行,但仍然存在内存泄漏。我也想知道这是否是正确的做法?

澄清问题/问题的位置:为什么我还有内存泄漏?并且,delete以前分配的内存有更好/更清晰的方法吗?

4 个答案:

答案 0 :(得分:2)

查看C ++ 11的smart_pointers,它们提供了分配内存的能力,当对象超出范围时,它将被自动释放。

#include <memory>
#include <iostream>

struct Foo {
    Foo() { std::cout << "Foo...\n"; }
    ~Foo() { std::cout << "~Foo...\n"; }
};

struct D { 
    void operator()(Foo* p) const {
        std::cout << "Call delete for Foo object...\n";
        delete p;
    }
};

int main()
{
    {
        std::cout << "constructor with no managed object\n";
        std::shared_ptr<Foo> sh1;
    }

    {
        std::cout << "constructor with object\n";
        std::shared_ptr<Foo> sh2(new Foo);
        std::shared_ptr<Foo> sh3(sh2);
        std::cout << sh2.use_count() << '\n';
        std::cout << sh3.use_count() << '\n';
    }

    {
        std::cout << "constructor with object and deleter\n";
        std::shared_ptr<Foo> sh4(new Foo, D());
    }
}

输出:

  

没有托管对象构造函数的构造函数,对象为Foo ... 2 2   ~Foo ...带对象和删除器的构造函数Foo ...为Foo调用删除   对象......〜Foo ......

http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

请记住,对于每个,在释放内存时应调用删除。如果本地指针被破坏并且在此之前没有释放内存,则它们可能是危险的。

面向对象C ++中的RAII paradigm专门用于简化资源管理(以及内存管理)。

如果灾难已经完成,您可以使用http://deleaker.com/或等效的内存泄漏搜索软件清理代码。

另外:如果您不能使用C ++ 11或者您不能使用支持C ++ 11的编译器,请自己动手实现智能指针,它应该不会太难并且肯定会有所帮助你的记忆问题。

答案 1 :(得分:2)

我知道您希望在重新分配这些成员之前释放Object3d::vertexObject3d::vertexNormalObject3d::face占用的内存。首先,您应该为Face3d提供自定义析构函数,以便您不再需要在包含类中关注它的成员。那就是:

face3d::~face3d() {
    if (iVertex) delete[] iVertex;
    if (iVertexNormal) delete[] iVertexNormal;
}

Object3d课程中,您可以使用专门的清理功能:

void Object3d::cleanup() {
    if (face) delete[] face;
    face = nullptr;
    if (vertex) delete[] vertex;
    vertex = nullptr;
    if (vertexNormal) delete[] vertexNormal;
    vertexNormal = nullptr;
    nVertex = 0;
    nFace = 0;
    nVertexNormal = 0;
}

顺便说一句,在析构函数Object3d::~Object3d()中,你也必须调用该函数。

答案 2 :(得分:0)

This question可能会回答你的问题。我认为你必须将void指针强制转换为特定的一个,比如int *,以使它工作。但是这种行为高度依赖于您使用的编译器。

编辑:使用智能指针的建议可能是解决问题的最简单,最安全的方法。

答案 3 :(得分:0)

使用std :: vector而不是手动管理的数组:

struct Face3d{
int nFaceV;
std::vector<int> iVertex;
std::vector<int> iVertexNormal;

Face3d():nFaceV(0){}
};

class Object3d{

public:

std::vector<Vector3d> vertex;
std::vector<Vector3d> vertexNormal;
std::vector<Face3d> face;

void LoadOBJ(char*);
Object3d():nVertex(0), nFace(0), vertex(NULL), face(NULL){}
Object3d(char*);
~Object3d(){}
};

这使您免于编写析构函数的负担。如上所述,这是C ++中RAII模式的例子,它应该用来代替手动资源管理。

作为一般性评论,公共数据成员几乎总是一个坏主意,因为它破坏了封装。 Object3d应该为客户端提供一些服务并保持其内部私有。