delete之后实例指针仍然可以正常使用

打算写一个可以限制容量的队列, 代码如下

#include <iostream>
using namespace std;

templateclass type >
class LimitedQueue {
public:
    LimitedQueue();
    ~LimitedQueue();
    
    void Remove();
    LimitedQueue RoundForEnqueue();
    void InsertBeforeLimitedQueue pnode );
    void SetDatatype newdata ) ;
    void Enqueuetype newdata ) ;
    void Print();
    void Clear();
    
    
public:
    LimitedQueue next;
    LimitedQueue prev;
    LimitedQueue head;
    type data;
    
};

templateclass type >
LimitedQueue<type>::LimitedQueue(  ) {
    head this;    
    next this;
    prev this;
    data NULL;
}


templateclass type >
LimitedQueue<type>::~LimitedQueue() {
    // cout << "delting data" << *data << endl;
    delete data;
    Remove();
}

templateclass type >
void LimitedQueue<type>::Remove() {
    prev->next next;
    next->prev prev;

    next this;
    prev this;
    head this;
}

// round , return the freed node , use that node to reuse data, then insert that node to the end
templateclass type >
LimitedQueue<type> * LimitedQueue<type>::RoundForEnqueue(  ) {
    LimitedQueue newhead head->next;
    head newhead;
    LimitedQueue pTravle next;
    whilepTravle->head != newhead ) {
        pTravle->head newhead;
        pTravle pTravle->next;
    }
    
    return head->prev;
}

templateclass type >
void LimitedQueue<type>::Enqueuetype newdata ) {
    LimitedQueue newnode new LimitedQueue();
    newnode->SetDatanewdata );
    
    // put it on the tail
    newnode->InsertBeforehead );
}

templateclass type >
void LimitedQueue<type>::Print() {
    LimitedQueue pnode head;
    cout << "call print" << endl;
    whilepnode->next != head ) {
         cout << *pnode->data << endl;
        pnode pnode->next;
    }
    cout << *pnode->data << endl;
}

templateclass type >
void LimitedQueue<type>::InsertBeforeLimitedQueue pnode ) {
    next pnode;
    prev pnode->prev;
    
    prev->next this;
    pnode->prev this;
    
    head pnode->head;
}


templateclass type >
void LimitedQueue<type>::SetDatatype newdata ) {
    data newdata;
}

templateclass type >
void LimitedQueue<type>::Clear() {
    
    LimitedQueue pnode head;
    // while ( pnode->next != head ) { 永远成立
    while pnode->next->next != head ) {
        delete pnode->next ;
        
    }
    // cout << "deleteing head->next node " << endl;
    delete pnode->next;
    // 现在只剩下一个节点
    delete pnode;// 相当于delete this
    // pnode->Print();
}

int main () {

    LimitedQueue<int> * head new LimitedQueue<int>();
    int 2;
    head->SetData( &) ;
    
    int pi new int;
    *pi 3;
    head->Enqueuepi );
    
    pi new int;
    *pi 4;
    head->Enqueuepi );
    
    pi new int;
    *pi 5;
    head->Enqueuepi );
    
    head->Print();
    
    cout << "=======================" << endl;
    
    head head->RoundForEnqueue();
    pi head->data;
    *pi 100;
    
    head->Print();
    
    cout << "=======================" << endl;
    
    head head->RoundForEnqueue();
    *(head->data) = 200;
    
    head->Print();
    
    head->Clear();
    
    head->Print() ; // should wrong; delete之后内存还在, 只不过随时可能变化
    
    
}

输出:

call print
2
3
4
5
=======================
call print
3
4
5
100
=======================
call print
4
5
100
200
delting data5
delting data100
deleteing head->next node
delting data200
delting data4
call print
4
call print
200

Clear函数用于释放node表示的数据以及节点本身, Clear执行之后, 节点和其保持的数据都应该被delete了, 所以随手加了一句使用已经被delete的指针, 预期执行的时候会报个错, 表明Clear正常的工作了. 执行的时候发现delete之后的实例指针以及实例中的数据都还在, 一切正常, 好像没有用delete一样. 根本不知道delete到底有没有起作用.

原因在于delete只是将那块内存释放, 但是并没有把里面的数据都擦除掉. 实际上操作系统执行删除文件也是同样的, 即使你永久性的删除, 即不是放到回收站, 数据仍然在磁盘上, 只不过在文件系统中已经看不到了, 如果之后再往磁盘上拷贝新的文件, 那些空间才会被覆盖. 如果删除之后再没有写入的操作, 这些文件是可以恢复的. delete与此类似. 被delete的内存如果没有被重新分配, 那么之前的指针仍然有效.

这个问题叫做"dangling pointer". 像这样的指针其行为是不确定的, danging pointer如果出了问题, 调试起来会很麻烦, 因为每次运行内存的分配释放过程可能都不一样, 那么dangling pointer的行为每次都会不同. 这样的bug根本无法重现, 也就很难发现.