为什么在删除类实例之后仍然可以访问它们?
为什么在删除类实例之后仍然可以访问它们?
我正在构建一个链表类,具有堆栈功能(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(){} /// 向列表中添加元素的函数。 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; } } /// 从列表中删除对象的函数。 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 << "删除对象后仍然可以访问:" << (*slider).getID() << endl; return end; } private: Node *root; Node *end; Node *slider; };
在NodeList::Node *pop()
函数中(其目的是删除最后一个元素并将上一个元素重置为列表的末尾),我在指针名为slider的指向的Node类
实例上调用delete。然而,即使在删除后,我仍然可以访问该实例并输出其成员。我不知道是否重要,但在删除时,该实例有三个不同的指针指向它。它们是:
- Node *slider;
- Node *end;
- 上一个类实例的Node::Node *nextNode;
我想此时应该提问:D
如果在删除后仍然可以访问实例成员,我如何知道它是否已正确删除?
我的代码会导致内存泄漏吗?
我猜最重要的问题是:我做错了什么吗?
P.S. 这里有几个变量(position2df; vector2df;
),它们来自Irrlicht游戏引擎。只是想指出这一点,以避免任何混淆。
如果我的问题表述含糊或不清楚,请原谅,我在在线提问方面并不很熟练。
为什么在删除对象之后仍然可以访问类实例?
当删除一个对象时,它并不会立即被覆盖。对象所占用的内存区域仅仅被标记为"可用"。在内存被重新分配并初始化为其他用途之前,该内存区域不会被覆盖。
由于无法控制内存何时以及为何目的被重新分配,因此在删除对象后永远不应该再次访问该内存。为了确保这一点,在删除对象之前,所有指向被删除对象的指针都应该被设置为null。
但是通常情况下,在删除之后将所有指针设置为null是不可能的,因为该指针可能已经被复制了多次,而且你不知道这些指针的具体位置。我个人认为这样的建议是误导性的,对于典型情况并没有帮助,而且很可能会让人误认为指针的使用可以变得更安全。
解决这个问题的方法是在删除对象之前,尽量避免复制指针,并确保所有指向该对象的指针都被设置为null。此外,还可以使用智能指针等工具来管理内存,以避免出现访问已删除对象的情况。在编写代码时,应该始终注意内存的正确释放和管理,以避免引发这类问题。
问题原因:删除实例后仍然可以访问的情况并不是内存泄漏,而是未定义的行为,即即将发生崩溃的情况。
问题解决方法:要避免删除实例后仍然访问的问题,可以在删除实例后,将对应的引用或指针置为null或者空值。这样,当试图访问已删除的实例时,程序会抛出异常或者执行错误处理代码,从而避免发生崩溃。
以下是一个示例代码,演示了删除实例后访问的问题及解决方法:
public class MyClass { // Some class members and methods public static void main(String[] args) { MyClass instance = new MyClass(); // Do something with the instance // Delete the instance instance = null; // Access the instance after deletion // This will lead to undefined behavior and may cause a crash // Some code here... // To avoid accessing deleted instances, set the reference to null MyClass anotherInstance = new MyClass(); // Do something with anotherInstance // Delete anotherInstance anotherInstance = null; // Access anotherInstance after deletion if (anotherInstance != null) { // This will not execute since anotherInstance is null // Handle the error or throw an exception } // Some code here... } }
在上述示例代码中,首先创建了一个名为instance的实例,并对其进行操作。然后将instance置为null,模拟删除实例的操作。接着,试图访问已删除的instance,这会导致未定义的行为和潜在的崩溃。
为了解决这个问题,我们在示例代码中创建了一个名为anotherInstance的新实例,并在删除anotherInstance后,使用if语句进行了判断,确保在访问已删除的实例时不会执行代码块。这样,即使尝试访问已删除的anotherInstance,程序也不会崩溃,而是执行错误处理代码或抛出异常。
删除实例后仍然访问可能导致未定义的行为和崩溃。为了避免这种情况发生,应在删除实例后将引用或指针置为null,以确保不会访问已删除的实例。