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 

私は理解していません。私が考えることができる唯一のことは、ルートノードがヒープに割り当てられる代わりにスタック上に作成されていることですが、newはC++でメモリが正しく割り当てられていることを確認していませんか?

+0

「addChild」の前にコードを投稿できますか?問題はそこにあるように見える – JaredPar

+0

あなたのサンプルコードはVALを一度出力します。 2番目のVAL出力はどこから取得していますか? – HighCommander4

+0

メインから1つ、インサートから1つ – Kristofer

答えて

3

私の問題は、挿入メソッドがBinarySearchTreeを値で返しますが、コピーコンストラクタが定義されていないということです。その結果、これはBinarySearchTreeの浅いコピーを作成し、それを返し、コピーのデストラクタを起動させます。これにより、ルートとして保存されたBstNodeが削除されますが、コピーされたBinarySearchTreeは元のツリーとBstNodesを共有しているため、元のツリーのメモリを破棄しています。取得しているエラーは、ノードに再度アクセスしようとすると、割り当て解除されたメモリにアクセスすることによるものです。

これを修正するには、insert関数でツリーへの参照を戻す(コピーが作成されない)か、コピーコンストラクターまたは代入演算子を定義します。理想的には、両方を行います。 :-)

これは役に立ちます。

+0

うわー、それは見えませんでしたが、デッド・ジムをデストラクタに追加すると、それが実行されていることが示されます。私たちは 'removeNode'の実装が不足しているためエラーにはなりません。任意のメモリの割り当てを解除します。 –

+0

これは、ありがとう!私は '* this'を返していたので、私はJavaとC#で練習したように、tree.insert(5).insert(10).insert(-3)などのinsert呼び出しを連鎖させることができました。私はC++で、同じことを達成するためにドットの代わりに参照解除 ' - >'を使用するべきであると思いますか? –

+1

@ AndrewRueckert- C++では、BinarySearchTree(オブジェクトのコピー)ではなくBinarySearchTree&(オブジェクトへの参照)を返します。 JavaとC#のトリックはここでも動作しますが、参照を返すことを明示的に述べる必要があります。 JavaおよびC#では、すべてのオブジェクトが参照渡しされますが、C++では値渡しがデフォルトです。 – templatetypedef