1

我一直在练习我的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 

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

+0

你可以发布'addChild'吗?问题似乎存在 – JaredPar 2012-02-14 08:35:05

+0

您的示例代码仅输出VAL一次。你从哪里得到第二个VAL输出? – HighCommander4 2012-02-14 08:36:12

+0

一个来自main,另一个来自insert – Kristofer 2012-02-14 08:36:55

回答

3

我认为这个问题是您的插入方法,通过值返回BinarySearchTree,但你没有拷贝构造函数定义。因此,这会使BinarySearchTree的一个浅表副本,返回它,并使副本的析构函数触发。然后删除存储为根的BstNode,但由于复制的BinarySearchTree与原始树共享BstNodes,因此您在原始树中废弃了内存。您遇到的错误是在您尝试再次访问节点时访问释放的内存。

为了解决这个问题,要么插入功能回到树(所以没有仿造而成)的引用或定义拷贝构造函数或赋值操作符。理想情况下,两个都做。 :-)

希望这有助于!

+0

哇,没看到,但是是加入了'他死Jim' COUT析构函数表明,它运行时,我们不会因为我们缺乏removeNode'的'执行出现错误,因此不释放任何内存。 – 2012-02-14 09:06:11

+0

这就是它,谢谢!我正在返回'* this',所以我可以链接插入调用 - tree.insert(5).insert(10).insert(-3)等 - 就像我被训练在Java和C#中做的一样。我想在C++中,我应该使用dereferencing' - >'而不是点来完成同样的事情? – 2012-02-14 09:08:20

+1

@ AndrewRueckert-在C++中,你将有函数返回一个BinarySearchTree&代替BinarySearchTree(参考对象)(对象的副本)。 Java和C#技巧在这里仍然有效,但你必须明确说明你将返回引用。在Java和C#中,所有对象都通过引用传递,但在C++中,传递值是默认值。 – templatetypedef 2012-02-14 09:10:42