我在C ++中有这段代码:
void printHeap (Heap<T> &heap)
{
typename list< HeapNode<T> >::iterator heapIterator = heap.heap.begin();
for( ; heapIterator != heap.heap.end(); ++heapIterator)
{
cout<<"element"<<endl;
}
}
这是堆的定义:
template <class T>
class Heap
{
public:
list <HeapNode<T> > heap;
HeapNode<T> *minValue;
BinomialHeap(HeapNode<T> *min = 0)
{
minValue = min;
}
T getMinimumKey()
{
return minValue->key;
}
void insert(T data)
{
HeapNode<T> tmp (data);
heap.push_back(tmp);
if(!minValue || minValue->key > tmp.key)
minValue = &tmp;
}
};
HeapNode.cpp 模板
class HeapNode
{
public:
int degree;
HeapNode<T> *parent;
list <HeapNode<T> *> sons;
T key;
HeapNode(T d, HeapNode<T> *parent = 0)
{
key = d;
this->parent = parent;
degree = 0;
}
};
我尝试过这段代码,但是我得到了一些意想不到的值:
BinomialHeap<int> heap;
heap.insert(4);
heap.insert(3);
heap.insert(2);
heap.insert(1);
cout<<heap.getMinimumKey() <<endl;
printHeap(heap);
cout<<heap.getMinimumKey();
第一个cout打印1(如预期的那样),但是在调用printHeap之后,即使我没有操作这个成员变量(第二个cout打印一个奇怪的数字),minValue也会改变。为什么会这样?它不应该打印相同的数字,因为我没有在该方法中修改minValue吗?
答案 0 :(得分:2)
void insert(T data)
{
HeapNode<T> tmp (data);
heap.push_back(tmp);
if(!minValue || minValue->key > tmp.key)
minValue = &tmp;
}
此代码已损坏。您创建一个临时对象,然后存储指向它的指针。但是一旦函数返回,对象就不再存在,因此指针指向任何东西。当你致电getMinimumKey
时,你会得到垃圾。我想您希望将minValue
设置为指向您推送到列表中的tmp
副本。
答案 1 :(得分:1)
但在调用printHeap之后,minValue会更改
这通常表示您正在进行越界数组访问,或通过无效指针访问。
void insert(T data)
{
HeapNode<T> tmp (data);
heap.push_back(tmp);
if(!minValue || minValue->key > tmp.key)
minValue = &tmp;
}
这里是...... tmp
是此函数的本地函数,当函数退出时它不再存在,将minValue
作为一个野指针。
要解决这个问题,只要minValue
没有改变,你就必须使minValue
指向保证不会被销毁的东西;或以其他方式实施您的minvalue-finder。
你可以使minValue
指向一个实际的列表元素,但是这仍然很危险,除非您还在列表可能有节点的每个可能的其他点检查minValue
从中删除。您还必须在copy-constructor和copy-assignment运算符中考虑minValue
;这些的默认版本将不再有效(它们会再次将minValue作为伪指针)。