【问题标题】:unexpected changes in member variables of an object对象成员变量的意外更改
【发布时间】:2014-06-21 04:32:05
【问题描述】:

我在 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;
    }
};

堆节点.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 之后,即使我没有操作此成员变量,minValue 也会发生变化(第二个 cout 打印一个奇怪的数字)。为什么会这样?它不应该打印相同的数字,因为我没有在那个方法中修改 minValue 吗?

【问题讨论】:

    标签: c++ oop data-structures


    【解决方案1】:
    void insert(T data)
    {
        HeapNode<T> tmp (data);
        heap.push_back(tmp);
        if(!minValue || minValue->key > tmp.key)
            minValue = &tmp;
    }
    

    此代码已损坏。您创建一个临时对象,然后存储一个指向它的指针。但是一旦函数返回,对象就不复存在了,所以指针指向任何东西。当您致电getMinimumKey 时,您会收到垃圾邮件。我想您想将minValue 设置为指向您推送到列表中的tmp 的副本。

    【讨论】:

    • 谢谢,如果我想指向列表中的元素?有没有办法访问该元素? minValue = &(*heap.end()) 会是一个好的解决方案吗?
    • list::back()(或您的建议)。但不要忘记,您必须在复制构造函数和复制赋值运算符中正确考虑这一点。 (或者,对于 C++11,删除它们。对于早期版本的 C++,将它们设为私有并且永远不要使用它们。)
    • 谢谢!非常感谢您的帮助。
    • 如果我正确理解了代码,那么parent 和sons 指针都会有同样的问题;因此,明智的做法是确保堆是不可复制和不可移动的,并且在从中删除项目时要非常小心
    • @MattMcNabb 可以从这类事情中学到的一个宝贵教训是,裸指针在 C++ 中几乎从来都不是正确的解决方案。
    【解决方案2】:

    但调用 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 指向一个实际的列表元素,但是这仍然很危险,除非您在列表可能从中删除节点的每个可能的其他点上检查minValue。您还必须在复制构造函数和复制赋值运算符中考虑minValue;这些的默认版本将不再工作(他们会再次将 minValue 作为虚假指针)。

    【讨论】:

    • 谢谢你,即使我没有选择你的答案,我也感谢你的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2011-09-02
    • 1970-01-01
    • 2014-10-21
    相关资源
    最近更新 更多