我有一个关于如何正确删除结构的问题,以及它在内部声明的各个指针。
我从已经运行的项目中提取了一个示例,它似乎无法正常工作,代码不会崩溃,但似乎我有一些“内存泄漏”。我不确定这是正确的措辞。问题是这些值并没有真正重置,并且在我下次启动课程时会保留在内存中。
下面的Sudocode:
标题
ProgramHeader.h
class ClassA : public publicClassA
{
public:
ClassA(void);
virtual ~ClassA();
private:
struct ApStruct{
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} fR;
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} f1kHz;
};
ApStruct* GetApStruct;
}
程序:
Program.cpp
#include "ProgramHeader.h"
ClassA::~ClassA()
{
//EDIT i did a typo my looks like this:
//delete ApStruct; //Wrong code
delete GetApStruct; //Corrected - however still not working
}
main()
{
GetApStruct = new ApStruct();
//Do Code
}
希望这一切都有点意义,
修改 我在代码中更新了一行错误 - 然而问题仍然是一样的。在实施解决方案之前,我将在下面了解一下。
编辑24/10/2015 我一直在尝试下面的一些建议,但我无法找到解决问题的办法,我必须承认我也很难将其缩小范围,这可能会导致问题。
我的代码是DLL的一部分。代码包装了一些我无法控制的源代码,因此我有限的选项如何使用构造函数和新的指针初始化。
我仍然认为我有内存泄漏问题的原因是,如果我在我的代码中添加“魔术浮点数”,我的函数输出会发生变化,即使浮点数 不 在任何地方使用 - 它只是宣布。
我在以下情况下获得了不同的结果:
当我再次重复上述内容时,我从第一次运行代码时获得了不同的结果,但之后它保持不变。
如果我包含魔术线似乎都有效???
更新了SudoCode:
Program.cpp
#include "ProgramHeader.h"
ClassA::~ClassA()
{
//EDIT i did a typo my looks like this:
//delete ApStruct; //Wrong code
delete GetApStruct; //Corrected - however still not working
}
main()
{
void initCode()
{
GetApStruct = new ApStruct();
float InitValue = 0.F
//Magic line:
float magicLine = 123456.f; //If this line is commented out i get different results in my code
//End Magic Line
fr.refA[0] = &InitValue;
fr.refA[0] = &InitValue;
fr.refA[0] = &InitValue;
fr.pVarA = &InitValue;
...
}
void CallCode()
{
float CallValue = 123.F
//Magic line:
float magicLine = 123456.f; //If this line is commented out i get different results in my code
//End Magic Line
fr.refA[0] = &CallValue;
fr.refA[0] = &CallValue;
fr.refA[0] = &CallValue;
fr.pVarA = &CallValue;
...
}
}
谢谢你的支持,
托马斯
答案 0 :(得分:1)
我建议使用以下内容进行分配和清理......
#include <iostream>
using namespace std;
class ClassA
{
public:
ClassA(void);
virtual ~ClassA();
private:
struct ApStruct {
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} fR;
struct
{
float *refA[2];
float *refB[2];
float *pVarA;
} f1kHz;
};
ApStruct* GetApStruct;
};
ClassA::ClassA(void) {
GetApStruct = new ApStruct{};
GetApStruct->fR.refA[0] = new float{ 1.f };
GetApStruct->fR.refA[1] = new float{ 2.f };
GetApStruct->fR.refB[0] = new float{ 3.f };
GetApStruct->fR.refB[1] = new float{ 4.f };
GetApStruct->fR.pVarA = new float { 0.f };
// do same for struct f1kHz
// ...
cout << "Construction" << endl;
}
ClassA::~ClassA()
{
if (GetApStruct != nullptr) {
if (GetApStruct->fR.refA[0] != nullptr) {
delete GetApStruct->fR.refA[0];
GetApStruct->fR.refA[0] = nullptr;
}
if (GetApStruct->fR.refA[1] != nullptr) {
delete GetApStruct->fR.refA[1];
GetApStruct->fR.refA[1] = nullptr;
}
if (GetApStruct->fR.refB[0] != nullptr) {
delete GetApStruct->fR.refB[0];
GetApStruct->fR.refB[0] = nullptr;
}
if (GetApStruct->fR.refB[1] != nullptr) {
delete GetApStruct->fR.refB[1];
GetApStruct->fR.refB[1] = nullptr;
}
if (GetApStruct->fR.pVarA != nullptr) {
delete GetApStruct->fR.pVarA;
GetApStruct->fR.pVarA = nullptr;
}
// do same for struct f1kHz
// ...
// finally
delete GetApStruct;
GetApStruct = nullptr;
}
cout << "Destruction" << endl;
}
int main() {
{
ClassA a;
}
system("pause");
return 0;
}
答案 1 :(得分:1)
当你创建一个结构/类对象时,它会保存该对象内存区域中的变量和指针(比如一个对象在内存中占用一些空间。让我们称之为一个框)。使用new()
或malloc()
初始化时,这些指针变量在对象数据所在的框外部给出空间。这些指针现在指向一个位于该对象的内存区域之外的内存区域。现在当对象被破坏时,对象占用的空间(我们称之为框)随着指针变量被破坏。指针指向的存储区仍在程序/进程存储区中。现在我们不知道它的地址是什么或它在哪里。这称为内存泄漏。为避免这种情况,我们需要使用delete
关键字取消分配指针引用的内存。我们现在可以自由行了。我尝试用下面的简单图形来说明它。 ObjectA框说明了它在内存中占用的区域。请注意,此容器/框包含本地变量,包括指针。指针指向一些内存位置,比如0xFFF ......并用绿线表示。当我们销毁ObjectA时,它只会破坏其中的所有内容,包括0xFFF地址。但是位于0xFFF的内存仍然在内存中分配。内存泄漏。
在析构函数中,使用delete
关键字显式取消分配内存。哇!我们保存了记忆。
答案 2 :(得分:1)
来自维基百科Resource Acquisition Is Initialization
资源获取初始化(RAII)是在C ++中突出使用的编程习惯用语。在RAII中,资源获取在对象创建期间由构造函数完成,而资源释放在对象销毁期间由析构函数完成。如果对象被正确销毁,则不会发生资源泄漏。
因此,您可以在构造函数中新建用于指针的内存,并在析构函数中释放它们:
ClassA::ClassA(void) {
GetApStruct = new ApStruct;
GetApStruct->fR.refA[0] = new float{ 1.f };
GetApStruct->fR.refA[1] = new float{ 2.f };
}
ClassA::~ClassA(void) {
delete []GetApStruct->fR.refA;
delete GetApStruct;
}
答案 3 :(得分:0)
好吧,让我直接说:
如果您使用的是new
或delete
,那么您做错了。
除非您是有经验的用户,或者您希望实施低级别的项目,否则请不要使用new
和delete
。
相反,使用现有的标准类来处理内存所有权,并在不必要时避免堆分配。作为奖励,您不仅可以避免内存泄漏,还可以避免悬空引用(即删除后使用内存)。
class ClassA : public publicClassA {
public:
private:
struct ApStruct{
struct
{
float refA[2];
float refB[2];
float pVarA;
} fR;
struct
{
float refA[2];
float refB[2];
float pVarA;
} f1kHz;
};
ApStruct GetApStruct;
}
是的,在你的情况下,它就像删除指针一样简单。否则,如果您想要动态数组(即编译时长度未知的数组),请使用std::vector
。