2017-01-09 10 views
0

現在、データ構造に関する書籍を読んでいて、側面でC++を学んでいます。私は単純なリンクリストを実装しようとしています。以下は、(問題を特定するために)最大2つの要素を取ることのできるリストのコードです。 間違っているのは、リスト内の次のノードへのポインタ宣言です。新しいNodeインスタンスを作成してそのインスタンスへのポインタを作成すると、ポインタは各メソッド呼び出しで同じ状態を維持するため、リスト内のすべての要素は同じノードを指しています。ただし、ポインタを直接作成すると、すべてが正常に動作します。各メソッド呼び出しでローカル変数ポインタが上書きされる

私が推測しているのは、ポインタ、参照、およびnewキーワードの基本的な誤解があることです。

以下のコードを自由に実行してください。作業コードはコメントアウトされています。このコードは正確にうまく設計されていないことを

#include <iostream> 
using namespace std; 

template <typename T> class Node { 
public: 
    Node(T nvalue) { 
     this->value = nvalue; 
     this->next = NULL; 
    } 
    T value; 
    Node *next; 
}; 

template <typename T> class LinkedList { 
    public: 
     Node<T> *head; 
     LinkedList() { 
      this->head = NULL; 
     } 
     void append(T newVal) { 
      // Correct 
      // Node<T>* newNode_ptr = new Node<T>(newVal); // newNode_ptr is different on each call 
      // Incorrect!? 
      Node<T> newNode = Node<T>(newVal); 
      Node<T> * newNode_ptr = &newNode; // newNode_ptr is the same on each call 
      cout << "New Node Address: " << newNode_ptr << endl; 
      if (!(this->head)) { 
       this->head = newNode_ptr; 
       cout << "Value 0: " << this->head->value << endl; 
      } else { 
       this->head->next = newNode_ptr; 
       cout << "Value 0: " << this->head->value << endl; 
       cout << "Value 1: " << this->head->next->value << endl; 
      } 
     } 
}; 

int main() { 
    LinkedList<int> list = LinkedList<int>(); 
    list.append(21); 
    cout << "..." << endl; 
    list.append(42); 
} 

は注意(いくつかのものがprivateである必要があり、using namespace stdは避けるべきです)。私はこのポインタのものが少し圧倒的なので、Pythonに精通しています。事前にあなたの助けをありがとう!

+2

***ノード * newNode_ptr =&newNode; *** 'newNode'が有効範囲外になると未定義の動作になります。 – drescherjm

+0

@drescherjm彼らは一緒に範囲外に行くので、問題は見えません。 – user

+2

ちょっとしたアドバイス - データ構造を作成するときは、最初に特定の種類のデータ構造を作成してください。あなたはそれが働いてテストされているときだけ、それをテンプレートに変えてください。 –

答えて

2
Node<T>* newNode_ptr = new Node<T>(newVal); 

これは2つのより正確な方法です。 newNde_ptrのアドレスが違うのは普通ですが、それはあなたが望むものです。各ノードは異なるノードであり、2つの異なるオブジェクトは同じアドレスを持つことができません! newのないバージョンは、というオブジェクトをスタックに作成するため、同じアドレスを返します。これは機能しません、すべてのノードは、append関数の最後に破棄されます。 appendの印刷部分を別の機能に移動すると、異常な結果が表示されます(クラッシュしない場合)。すべてのポインタが同じアドレス(あなたの場合)を指しており、というアドレスの値を出力するところでが有効なノードになると、クラッシュは表示されません。ただし、これは未定義の動作であり、さまざまな理由で変更される可能性があります。

フリーストア(malloc/freeのヒープ)とスタックの違いは、C++の基本的な概念です。あなたはそれについてhereを読むべきです。

2つの正しい方法を見た理由は、あなたのノードをdeleteに覚えておく必要があるということです。より良い方法は、rawポインタを使用することを奨励する(そして他のかもしれない)ことを避けるために、rawポインタの代わりにstd::unique_ptrを使用することです。

+1

さらに良い、 'std :: unique_ptr >' – SergeyA

+0

あなたの答えをありがとう!私はそれが正しい方法であることを知っています、私はちょうど他のソリューションがうまくいかなかったのだろうかと思っていました。私が最初に 'Node'オブジェクトを初期化してから関連するポインタを取得する私の2番目の解決策を修正できますか? – Nico

+2

@Nicoいいえ、その解決策を働かせることはできません。あなたはある種のメモリ割り当てを行う必要があります。オブジェクトがスタック上に作成された場合、そのオブジェクトはそのスコープの最後に生き残ることはできません。最も近い解決策は、別のインスタンスに移動することです([移動コンストラクタを参照](http://en.cppreference.com/w/cpp/language/move_constructor))。これはあなたのケースでは機能しません。これは、 'Node'型が別の' Node'と値を含んでいることを意味します。これは 'sizeof(Node)= sizeof(Node)+ sizeof(T)'を意味します。 –

関連する問題