所以我正在构建一个链表类,具有类似堆栈的功能(LIFO),用于保存Node类的实例:
enum Sides{NorthWest=0, North=1, NorthEast=2, West=3, East=4, SouthWest=5, South=6, SouthEast=7};
class Node
{
public:
Node(position2df pos, int id):nextNode(NULL)
{
position=pos;
ID=id;
}
~Node(){}
position2df getPosition(){return position;}
int getID(){return ID;}
void setPeripheralID(Sides side, int id){peripheralID[side]=id;}
int getPeripheralID(Sides side){return peripheralID[side];}
Node *nextNode;
private:
position2df position;
int ID;
int peripheralID[8];
};
class NodeList
{
public:
NodeList()
{
root=NULL;
end=NULL;
}
~NodeList(){}
/// Function for adding elements to the list.
void push(position2df pos, int id)
{
if(root==NULL)
{
root=new Node(pos, id);
end=root;
}
else
{
Node *newend=new Node(pos, id);
end->nextNode=newend;
end=end->nextNode;
}
}
/// Function for removing objects from the list.
Node *pop()
{
slider=root;
Node *previous;
Node *next=slider;
for(previous=NULL; next!=NULL; next=slider->nextNode)
{
previous=slider;
slider=next;
}
delete slider;
end=previous;
cout << "Can still access deleted object: " << (*slider).getID() << endl;
return end;
}
private:
Node *root;
Node *end;
Node *slider;
};
在NodeList::Node *pop()
函数中(其目的是删除最后一个元素并将前一个元素重置为列表的末尾),我在Node class
指向的实例上调用delete(指针名称)滑块。但是,即使删除它,我仍然可以访问该实例并输出其成员。我不知道它是否重要,但实例有三个不同的指针指向它删除时。他们是:
我想在这一点上有一个问题是:D
如果我在删除后仍然可以访问实例成员,我怎么知道它是否被正确删除了?
我的代码会导致内存泄漏吗?
我想最终的问题是:我做错了吗?
P.S。这里有一些变量(position2df; vector2df;
)来自Irrlicht游戏引擎。只是想指出这一点,以避免任何混淆。
如果我对这篇文章含糊不清或不清楚,请原谅我,但在网上提问时我不是很熟练。
答案 0 :(得分:2)
如果我在删除后仍然可以访问实例成员,我怎么知道它是否被正确删除了?
只需信任运行时库:如果您调用delete
,则会删除该事物,即句点。一旦你告诉系统你不再需要内存,你放弃了它 - 它不再是你的了。系统会根据可用内存对其进行计数以重新分配,因此可以根据请求将其提供给程序的其他部分。您仍然可以访问该内存,甚至可以在放弃之前找到它们,但这是未定义的行为。
我的代码会导致内存泄漏吗?
不,因为你释放了你分配的内存。
我想最终的问题是:我做错了吗?
是 - 访问解除分配对象的内存是错误的(未定义的行为)。除此之外,它看起来很好。
答案 1 :(得分:1)
如果删除后访问的内容不是泄漏,而是未定义的行为:即等待发生崩溃。
答案 2 :(得分:0)
删除的对象不会立即被覆盖。它们所在的存储区域仅标记为“可自由使用”。在重新分配和初始化内存以用于其他目的之前,不会覆盖它。
您无法控制何时以及为何发生这种情况,因此在删除内存后您永远不应该访问内存。为了确保这一点,所有指向已删除对象的指针都应该在删除之前设置为null。
答案 3 :(得分:0)
使用new和delete时,您正在使用动态内存:您要么保留一个内存块,要么将其释放。在释放时,它只是注释为免费使用,因此可以在需要时重复使用。但是,该计划并未专门用于清理该存储区域。
有一个指向已释放的内存区域的指针是可能的,并且您可以从那里读取数据,但要小心,因为当程序需要保留更多内存时,可能会随时替换找到的数据。
访问已释放的内存区域始终是危险的,可能会导致程序崩溃,甚至更糟糕的是故障。
答案 4 :(得分:0)
如果我删除后仍然可以访问实例成员,我该如何操作 知道它是否被正确删除了?
在调用delete
之后,内存不再是您的,而对象被视为已删除
我的代码会导致内存泄漏吗?
不,如果你没有调用delete
那么它就是泄漏,但是你在这里释放了之前分配的内存,所以没关系。
我想最终的问题是:我做错了吗?
是的,在调用delete
后你不应该认为还有你的对象,它是未定义的行为
答案 5 :(得分:0)
为什么删除后仍然可以访问类实例?
你做不到。
如果您仍然有指向包含该对象的内存的指针,您可能会或可能无法访问其残余;或者可能是自删除对象以来创建的另一个不相关的对象。如果你非常幸运,内存可能已被取消映射,并且你会得到一个友好的分段错误来指出错误,但这通常只发生在非常大的对象上。
简而言之,取消引用指向已删除对象的指针会产生未定义的行为。
我怎么知道它是否被正确删除了?
通过了解程序何时删除它,并确保之后不使用任何悬空指针。如果您使用原始指针并直接调用delete
,这非常棘手,这就是为什么您通常应该使用容器和智能指针等RAII类型管理动态内存。
我的代码会导致内存泄漏吗?
据我所见,pop
功能没有泄漏;如果你使用智能指针,你可以使它更明显正确。
析构函数不会删除任何内容,除非你还有其他东西负责删除列表的内容,否则当列表被销毁时你会泄漏其中的任何内容。
我想最终的问题是:我做错了吗?
如果您确实添加了析构函数来修复泄漏,那么您还需要添加(或删除)复制构造函数和复制赋值运算符,以防止在复制列表时双重删除。这有时称为Rule of Three,在编写资源管理类时非常重要。如果您使用智能指针,他们会为您处理所有这些,您可以遵循更简单的“零规则”(即让编译器为您生成这三件事)。