我有一个带有几个指针成员的类,可以重新分配。当我使用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
以前分配的内存有更好/更清晰的方法吗?
答案 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::vertex
,Object3d::vertexNormal
和Object3d::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应该为客户端提供一些服务并保持其内部私有。