所谓的野指针,实际上就是指针内存释放了之后,还继续调用,然后造成堆破坏。
这样的错误在刚开始是检测不出来的,只有在New的时候进行堆检测才会检测出来。
下面是我遇到的一个野指针,很隐蔽。只是有概率的出现野指针。
这是一个多线程的问题,首先在主线程进行removeSocket(),正常情况下,removeSocket会执行break,子线程是一个循环
while (getNowSocket() && getNowSocket()->GetSocketStatus()==SOCKET_STATUS_CONNECT)
{
if(this->getNowSocket()->OnSocketNotifyRead() == -1)
{
break;
}
}
下面是removeSocket的方法
//移除套接字
void removeSocket(){
if(m_pSocket != NULL)
{
if(m_pSocket->GetSocketStatus()==SOCKET_STATUS_CONNECT)
{
m_pSocket->CloseSocket();
}
if(m_pSocket != NULL) CC_SAFE_DELETE(m_pSocket);
}
};
这样做是十分危险的,因为虽然在循环里调用了break进行清除,但是由于网络的不确定性,很可能在你清除Socket的时候,刚好运行到循环判断的时候,这样就造成了野指针,然后程序崩溃。所以delete socket可以转到线程结束的时候调用。
9.17补充:
其实上面所说的并非是真正造成野指针的原因,真正的原因还在多线程的使用,主线程调用removeSocket是执行关闭Socket,但是在关闭的某一时刻子线程就已经知道主线程要关闭Socket了,就会自动执行关闭代码,如果照原来的写法,在线程结束的时候调用,也有可能在线程结束的时候removeSocket没有执行完,造成野指针。
下面是给出的解决方法,有两种:
1.退出的线程并不执行delete操作,每次调用网络循环子线程的时候检测变量是否存在,如果存在就delete
2.做一个状态变量,当removeSocket执行完成的时候状态设为完全关闭,在子线程中使用循环检测,如果没有完全关闭,则循环等待,如果完全关闭则delete
第一种方法简单方便,第二种方法逻辑上略复杂,而且略代码冗余。
但是第二种方法可以及时释放内存,使用哪种方法就见仁见智咯。