最近在研究一个算法,为了验证其效率就随手编写了一个代码。本以为没什么问题,结果一运行程序就卡住导致运行出错。
额。。。写个程序有Bug很正常的事情嘛,然而,就是这个Bug花了我一天的时间找错误。更令我沮丧的是,错误的源头竟然是。。。(买个关子,有兴趣的读者可以看看下面的伪代码找找错误,错误分析见最后)
我将C++代码主要部分列出,读者可以猜猜(错误新人也可能找到哦,主要是我太蠢了,哈哈 )
// 一个点的数据结构
class Point{
...
}
queue<Point*> Q; // 一个用于保存点的队列
DS ds; // 一个用于组织点集的数据结构
// 检查该点的值是否满足要求
bool ValueCheck(Point *p){
...
}
// 检查该点是否满足插入ds的要求
bool InsertCheck(Point *p){
...
}
// 将一个点插入到ds中
bool Insert(Point *p){
if(InsertCheck(p)){ //满足
ds.insert(p);
return true;
}
else return false;
}
void main(){
...
//假设Q中已经存放了许多点的地址,且每个地址都指向一个具体的Point
while(!Q.empty()){
Point *p = Q.pop();
if(Insert(p) && ValueCheck(p)){
...
}
else{
delete p;
}
}
...
}
如果运行程序,一个非常有意思的现象是ds中的一些点不是原先Q中保存的点,同时在我编写的代码中,经常会导致代码运行错误,但有时候却可以正常运行。
错误分析:
其实,很显然这是一个关于内存不正当使用的一个问题。错误的原因就在Insert ( p )这句话这,如果一个点满足插入条件并插入ds中,但却不满足值检查(ValueCheck)条件,就会导致else语句块执行,也就是删除该点所在的内存空间,从而在最后查点的时候发现有异常的点。
一个很简单的办法是修改if(Insert( p ) && ValueCheck( p ))为if(ValueCheck( p ) && Insert( p )),即利用&&的短路机制,只有在满足值检查后,再进行插入检查和插入操作。
这篇文章主要是想提醒新人们,在new和delete时一定要仔细检查啊,千万不要和作者一样犯这么低级的错误。。。。。(= m =)