【问题标题】:Member pointer being overwritten on function return?成员指针在函数返回时被覆盖?
【发布时间】:2012-02-14 08:24:47
【问题描述】:

我一直在练习我的 C++,因为它从大学开始就有点生疏了,而且我遇到了一个奇怪的问题,即我的函数一返回,成员值就会被覆盖。

template <class T>
class BstNode
{
    public:
        T value;
        BstNode<T>* left;
        BstNode<T>* right;
        BstNode<T>* parent;

        BstNode()
        { left = right = parent = NULL; }
        BstNode(T value)
        { this->value=value; left=right=parent=NULL;}
        BstNode(T value, BstNode<T>* parent)
        { this->value=value; this->parent=parent; left=right=NULL;}
};

template <class T>
class BinarySearchTree 
{
    protected:
        BstNode<T>* root;

        void removeNode(BstNode<T>* node);
        void addChild(T value, BstNode<T>* node);
        BstNode<T>* find(T value, BstNode<T>* node);
    public:
        BinarySearchTree()
        { root = NULL; }
        ~BinarySearchTree()
        { removeNode(root); }

        BinarySearchTree<T> insert(T value);
        bool contains(T value);
        BinarySearchTree<T> remove(T value);

        void print();

        BstNode<T>* getRoot() {return root;}

};

template <class T>
BinarySearchTree<T> BinarySearchTree<T>::insert(T value)
{
    if (root == NULL)
    {
        root = new BstNode<T>(value);       
    }
    else
    {
        addChild(value, root);
    }
    cout << "VAL: " << root->value << endl << "LEFT: " << root->left << endl << "RIGHT: "<< root->right << endl << "ADDR: " << root <<endl;
    return *this;
}
template <class T>
void BinarySearchTree<T>::addChild(T value, BstNode<T>* node)
{

    if (value > node->value)
    {
        cout <<"\tgt"<<endl;
        if (node->right == NULL)
        {
            node->right = new BstNode<T>(value, node);
        }
        else
        {
            addChild(value, node->right);
        }
    }
    else
    {
        cout<<"\tlte"<<endl;
        if (node->left == NULL)
        {
            node->left = new BstNode<T>(value, node);
        }
        else
        {
            addChild(value, node->left);
        }
    }
}

// [other member functions]


int main()
{
    BinarySearchTree<int> tree;
    BstNode<int> *n;
    n = tree.getRoot();
    cout << "ADDR: " << n <<endl<<endl;
    tree.insert(5);
    n = tree.getRoot();

    cout << "VAL: " << n->value << endl << "LEFT: " << n->left << endl << "RIGHT: "<< n->right << endl << "ADDR: " << n << endl;
    return 1;
}

我的函数的输出是:

$ ./bst
ADDR: 0

VAL: 5
LEFT: 0
RIGHT: 0
ADDR: 0xa917c8

VAL: 11085080
LEFT: 0xa917a8
RIGHT: 0
ADDR: 0xa917c8

我不明白为什么根节点中的值发生了变化,但指针仍然指向同一位置。我唯一能想到的是根节点是在堆栈上创建的,而不是在堆中分配的,但是new 不确保在 C++ 中正确分配了内存?

【问题讨论】:

  • 你能把代码发到addChild吗?问题似乎在那里
  • 您的示例代码仅输出 VAL 一次。您从哪里获得第二个 VAL 输出?
  • 一个来自main,一个来自ins
  • 在 main() 和 BinarySearchTree::insert() 中有一个 val 输出。插入中的一个正在打印正确/预期的值,而主要的一个正在打印随机/垃圾值。
  • templatetypedef 有一个很好的答案。至于为什么它对我们有用,我们没有 removeNode 的实现,所以树的析构函数什么也没做。

标签: c++ pointers data-structures binary-search-tree memory-corruption


【解决方案1】:

我认为问题在于您的插入方法按值返回 BinarySearchTree,但您没有定义复制构造函数。因此,这会生成 BinarySearchTree 的浅表副本,将其返回,并导致副本的析构函数触发。然后,这会删除存储为根的 BstNode,但是由于复制的 BinarySearchTree 与原始树共享 BstNode,因此您正在破坏原始树中的内存。当您尝试再次访问节点时,您遇到的错误是访问已释放的内存。

要解决这个问题,要么让插入函数返回对树的引用(因此不进行复制),要么定义一个复制构造函数或赋值运算符。理想情况下,两者都做。 :-)

希望这会有所帮助!

【讨论】:

  • 哇,没看到,但是在析构函数中添加 He dead Jim cout 表明它正在运行,我们没有收到错误,因为我们缺少 removeNode 的实现因此不要释放任何内存。
  • 就是这样,谢谢!我正在返回*this,这样我就可以将插入调用链接在一起——tree.insert(5).insert(10).insert(-3) 等——就像我在 Java 和 C# 中受过训练一样。我想在 C++ 中,我应该使用取消引用 -&gt; 而不是点来完成同样的事情?
  • @AndrewRueckert- 在 C++ 中,您可以让函数返回 BinarySearchTree&(对对象的引用)而不是 BinarySearchTree(对象的副本)。 Java 和 C# 技巧在这里仍然有效,但您必须明确声明您将返回引用。在 Java 和 C# 中,所有对象都是通过引用传递的,但在 C++ 中,按值传递是默认值。
猜你喜欢
  • 2018-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
  • 2012-02-16
  • 1970-01-01
相关资源
最近更新 更多